mirror of
https://github.com/correl/mage.git
synced 2024-12-24 11:50:45 +00:00
Merge branch 'master' of https://github.com/magefree/mage
This commit is contained in:
commit
34e9c2fdfb
118 changed files with 3090 additions and 1075 deletions
|
@ -168,8 +168,13 @@
|
|||
}
|
||||
}
|
||||
if (card instanceof StackAbilityView) {
|
||||
// replace ability by original card
|
||||
CardView tmp = ((StackAbilityView) card).getSourceCard();
|
||||
tmp.overrideRules(card.getRules());
|
||||
tmp.setChoosable(card.isChoosable());
|
||||
tmp.setPlayable(card.isPlayable());
|
||||
tmp.setPlayableAmount(card.getPlayableAmount());
|
||||
tmp.setSelected(card.isSelected());
|
||||
tmp.setIsAbility(true);
|
||||
tmp.overrideTargets(card.getTargets());
|
||||
tmp.overrideId(card.getId());
|
||||
|
|
|
@ -112,8 +112,13 @@ public class StackDialog extends IDialogPanel {
|
|||
for (CardView card : cards.values()) {
|
||||
|
||||
if (card instanceof StackAbilityView) {
|
||||
// replace ability by original card
|
||||
CardView tmp = ((StackAbilityView) card).getSourceCard();
|
||||
tmp.overrideRules(card.getRules());
|
||||
tmp.setChoosable(card.isChoosable());
|
||||
tmp.setPlayable(card.isPlayable());
|
||||
tmp.setPlayableAmount(card.getPlayableAmount());
|
||||
tmp.setSelected(card.isSelected());
|
||||
tmp.setIsAbility(true);
|
||||
tmp.overrideTargets(card.getTargets());
|
||||
tmp.overrideId(card.getId());
|
||||
|
|
|
@ -56,6 +56,21 @@
|
|||
<artifactId>gson</artifactId>
|
||||
<version>2.8.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<!-- to get the reference to local repository with com\googlecode\jspf\jspf-core\0.9.1\ -->
|
||||
<repositories>
|
||||
|
@ -82,7 +97,10 @@
|
|||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<finalName>mage-common</finalName>
|
||||
|
|
41
Mage.Common/src/main/java/mage/utils/FluentBuilder.java
Normal file
41
Mage.Common/src/main/java/mage/utils/FluentBuilder.java
Normal file
|
@ -0,0 +1,41 @@
|
|||
package mage.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A base class for fluent, immutable, composable builders.
|
||||
*
|
||||
* @see <a href="https://github.com/fburato/functionalutils/blob/master/utils/src/main/java/com/github/fburato/functionalutils/utils/Builder.java">Builder</a>
|
||||
*/
|
||||
public abstract class FluentBuilder<ToBuild, RealBuilder extends FluentBuilder<ToBuild, RealBuilder>> {
|
||||
|
||||
final ArrayList<Consumer<RealBuilder>> buildSequence;
|
||||
private final Supplier<RealBuilder> newReference;
|
||||
|
||||
protected FluentBuilder(Supplier<RealBuilder> newReference) {
|
||||
this.buildSequence = new ArrayList<>();
|
||||
this.newReference = newReference;
|
||||
}
|
||||
|
||||
private RealBuilder copy() {
|
||||
final RealBuilder realBuilder = newReference.get();
|
||||
realBuilder.buildSequence.addAll(buildSequence);
|
||||
return realBuilder;
|
||||
}
|
||||
|
||||
protected abstract ToBuild makeValue();
|
||||
|
||||
public RealBuilder with(Consumer<RealBuilder> consumer) {
|
||||
final RealBuilder nextBuilder = this.copy();
|
||||
nextBuilder.buildSequence.add(consumer);
|
||||
return nextBuilder;
|
||||
}
|
||||
|
||||
public ToBuild build() {
|
||||
final RealBuilder instance = this.copy();
|
||||
instance.buildSequence.forEach(c -> c.accept(instance));
|
||||
return instance.makeValue();
|
||||
}
|
||||
}
|
|
@ -121,8 +121,17 @@ public class CardView extends SimpleCardView {
|
|||
|
||||
protected Card originalCard = null;
|
||||
|
||||
/**
|
||||
* Non game usage like deck editor
|
||||
*
|
||||
* @param card
|
||||
*/
|
||||
public CardView(Card card) {
|
||||
this(card, null, false);
|
||||
this(card, (Game) null);
|
||||
}
|
||||
|
||||
public CardView(Card card, Game game) {
|
||||
this(card, game, false);
|
||||
}
|
||||
|
||||
public CardView(Card card, SimpleCardView simpleCardView) {
|
||||
|
@ -450,7 +459,7 @@ public class CardView extends SimpleCardView {
|
|||
|
||||
Card secondSideCard = card.getSecondCardFace();
|
||||
if (secondSideCard != null) {
|
||||
this.secondCardFace = new CardView(secondSideCard);
|
||||
this.secondCardFace = new CardView(secondSideCard, game);
|
||||
this.alternateName = secondCardFace.getName();
|
||||
this.originalName = card.getName();
|
||||
}
|
||||
|
@ -464,7 +473,7 @@ public class CardView extends SimpleCardView {
|
|||
if (card instanceof ModalDoubleFacesCard) {
|
||||
this.transformable = true; // enable GUI day/night button
|
||||
ModalDoubleFacesCard mdfCard = (ModalDoubleFacesCard) card;
|
||||
this.secondCardFace = new CardView(mdfCard.getRightHalfCard());
|
||||
this.secondCardFace = new CardView(mdfCard.getRightHalfCard(), game);
|
||||
this.alternateName = mdfCard.getRightHalfCard().getName();
|
||||
this.originalName = card.getName();
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import mage.abilities.effects.Effect;
|
|||
import mage.cards.Card;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameState;
|
||||
import mage.game.command.Emblem;
|
||||
import mage.game.command.Plane;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
@ -29,7 +28,7 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Uses for card render tests
|
||||
* Non game usage like card render tests
|
||||
*
|
||||
* @param cardViews
|
||||
*/
|
||||
|
@ -39,6 +38,11 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Non game usage like deck editor
|
||||
*
|
||||
* @param cards
|
||||
*/
|
||||
public CardsView(Collection<? extends Card> cards) {
|
||||
for (Card card : cards) {
|
||||
this.put(card.getId(), new CardView(card));
|
||||
|
@ -116,9 +120,9 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
|
|||
if (abilityView == null) {
|
||||
CardView sourceCardView;
|
||||
if (isPermanent) {
|
||||
sourceCardView = new CardView((Permanent) sourceObject);
|
||||
sourceCardView = new CardView((Permanent) sourceObject, game);
|
||||
} else if (isCard) {
|
||||
sourceCardView = new CardView((Card) sourceObject);
|
||||
sourceCardView = new CardView((Card) sourceObject, game);
|
||||
} else {
|
||||
sourceCardView = new CardView(sourceObject, game);
|
||||
}
|
||||
|
@ -164,14 +168,4 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
|
|||
+ abilities.stream().map(a -> a.getClass().getSimpleName() + " - " + a.getRule()).collect(Collectors.joining("\n")));
|
||||
}
|
||||
}
|
||||
|
||||
public CardsView(Collection<? extends Ability> abilities, GameState state) {
|
||||
for (Ability ability : abilities) {
|
||||
Card sourceCard = state.getPermanent(ability.getSourceId());
|
||||
if (sourceCard != null) {
|
||||
this.put(ability.getId(), new AbilityView(ability, sourceCard.getName(), new CardView(sourceCard)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ public class GameView implements Serializable {
|
|||
stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, card.getName(), new CardView(card, game, false, false, false)));
|
||||
}
|
||||
} else {
|
||||
stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, "", new CardView(card)));
|
||||
stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, "", new CardView(card, game)));
|
||||
}
|
||||
if (card.isTransformable()) {
|
||||
updateLatestCardView(game, card, stackObject.getId());
|
||||
|
@ -103,7 +103,7 @@ public class GameView implements Serializable {
|
|||
} else if (object != null) {
|
||||
if (object instanceof PermanentToken) {
|
||||
PermanentToken token = (PermanentToken) object;
|
||||
stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, token.getName(), new CardView(token)));
|
||||
stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, token.getName(), new CardView(token, game)));
|
||||
checkPaid(stackObject.getId(), (StackAbility) stackObject);
|
||||
} else if (object instanceof Emblem) {
|
||||
CardView cardView = new CardView(new EmblemView((Emblem) object));
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
|
||||
package mage.view;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.TurnFaceUpAbility;
|
||||
import mage.cards.Card;
|
||||
|
@ -12,8 +8,11 @@ import mage.game.permanent.Permanent;
|
|||
import mage.game.permanent.PermanentToken;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class PermanentView extends CardView {
|
||||
|
@ -36,8 +35,8 @@ public class PermanentView extends CardView {
|
|||
private final boolean attachedToPermanent;
|
||||
|
||||
public PermanentView(Permanent permanent, Card card, UUID createdForPlayerId, Game game) {
|
||||
super(permanent, game, (permanent.getControllerId() == null) ? false : permanent.getControllerId().equals(createdForPlayerId));
|
||||
this.controlled = (permanent.getControllerId() == null) ? false : permanent.getControllerId().equals(createdForPlayerId);
|
||||
super(permanent, game, permanent.getControllerId() != null && permanent.getControllerId().equals(createdForPlayerId));
|
||||
this.controlled = permanent.getControllerId() != null && permanent.getControllerId().equals(createdForPlayerId);
|
||||
this.rules = permanent.getRules(game);
|
||||
this.tapped = permanent.isTapped();
|
||||
this.flipped = permanent.isFlipped();
|
||||
|
@ -59,7 +58,7 @@ public class PermanentView extends CardView {
|
|||
} else {
|
||||
if (card != null) {
|
||||
// original may not be face down
|
||||
original = new CardView(card);
|
||||
original = new CardView(card, game);
|
||||
} else {
|
||||
original = null;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
|
||||
package mage.view;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import mage.cards.Card;
|
||||
import mage.counters.Counters;
|
||||
import mage.designations.Designation;
|
||||
|
@ -22,6 +14,9 @@ import mage.game.permanent.Permanent;
|
|||
import mage.players.Player;
|
||||
import mage.players.net.UserData;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
@ -105,7 +100,7 @@ public class PlayerView implements Serializable {
|
|||
}
|
||||
Card cardOnTop = (player.isTopCardRevealed() && player.getLibrary().hasCards())
|
||||
? player.getLibrary().getFromTop(game) : null;
|
||||
this.topCard = cardOnTop != null ? new CardView(cardOnTop) : null;
|
||||
this.topCard = cardOnTop != null ? new CardView(cardOnTop, game) : null;
|
||||
if (player.getUserData() != null) {
|
||||
this.userData = player.getUserData();
|
||||
} else {
|
||||
|
|
|
@ -27,6 +27,8 @@ public class StackAbilityView extends CardView {
|
|||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// in GUI: that's view will be replaced by sourceCard, so don't forget to sync settings like
|
||||
// selectable, chooseable, etc. Search by getSourceCard
|
||||
private final CardView sourceCard;
|
||||
|
||||
public StackAbilityView(Game game, StackAbility ability, String sourceName, CardView sourceCard) {
|
||||
|
|
123
Mage.Common/src/test/java/mage/remote/ConnectionTest.java
Normal file
123
Mage.Common/src/test/java/mage/remote/ConnectionTest.java
Normal file
|
@ -0,0 +1,123 @@
|
|||
package mage.remote;
|
||||
|
||||
import mage.utils.FluentBuilder;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class ConnectionTest {
|
||||
|
||||
static class ConnectionBuilder extends FluentBuilder<Connection, ConnectionBuilder> {
|
||||
|
||||
public int port;
|
||||
public String host;
|
||||
public String parameter;
|
||||
|
||||
private ConnectionBuilder() {
|
||||
super(ConnectionBuilder::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Connection makeValue() {
|
||||
final Connection result = new Connection(parameter);
|
||||
result.setHost(host);
|
||||
result.setPort(port);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private ConnectionBuilder baseBuilder() {
|
||||
return new ConnectionBuilder();
|
||||
}
|
||||
|
||||
class TestsTemplate {
|
||||
final ConnectionBuilder testeeBuilder;
|
||||
|
||||
TestsTemplate(ConnectionBuilder testeeBuilder) {
|
||||
this.testeeBuilder = testeeBuilder;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("produce the expected scheme")
|
||||
void scheme() throws Exception {
|
||||
final URI testee = make(testeeBuilder);
|
||||
assertThat(testee.getScheme()).isEqualTo("bisocket");
|
||||
}
|
||||
|
||||
URI make(ConnectionBuilder builder) {
|
||||
try {
|
||||
return new URI(builder.build().getURI());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("generate the expected port")
|
||||
void port() {
|
||||
final int expected = RandomUtils.nextInt(1000, 65000);
|
||||
final int port = make(testeeBuilder.with(c -> c.port = expected)).getPort();
|
||||
|
||||
assertThat(port).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("generate the expected serialisation parameter")
|
||||
void serialisation() {
|
||||
final String query = make(testeeBuilder).getQuery();
|
||||
|
||||
assertThat(query).contains("serializationtype=jboss");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("generate the expected threadpool parameter")
|
||||
void threadpool() {
|
||||
final String parameter = RandomStringUtils.randomAlphanumeric(12);
|
||||
final String query = make(testeeBuilder.with(c -> c.parameter = parameter)).getQuery();
|
||||
|
||||
assertThat(query).contains("onewayThreadPool=mage.remote.CustomThreadPool" + parameter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("getUri when host is localhost should")
|
||||
class LocalhostTest extends TestsTemplate {
|
||||
|
||||
LocalhostTest() {
|
||||
super(baseBuilder().with(c -> c.host = "localhost"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("generate an ipv4 as host")
|
||||
void ipv4Gen() {
|
||||
final String host = make(testeeBuilder).getHost();
|
||||
|
||||
assertThat(host).matches("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+");
|
||||
}
|
||||
}
|
||||
|
||||
private final String randomHost = RandomStringUtils.randomAlphabetic(15);
|
||||
|
||||
@Nested
|
||||
@DisplayName("getUri when host is not localhost should")
|
||||
class StandardHostTest extends TestsTemplate {
|
||||
StandardHostTest() {
|
||||
super(baseBuilder().with(c -> c.host = randomHost));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("generate the selected host as host")
|
||||
void hostGen() {
|
||||
final String host = make(testeeBuilder).getHost();
|
||||
|
||||
assertThat(host).isEqualTo(randomHost);
|
||||
}
|
||||
}
|
||||
}
|
116
Mage.Common/src/test/java/mage/utils/FluentBuilderTest.java
Normal file
116
Mage.Common/src/test/java/mage/utils/FluentBuilderTest.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
package mage.utils;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
|
||||
public class FluentBuilderTest {
|
||||
|
||||
|
||||
private ABuilder baseBuilder() {
|
||||
return new ABuilder();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("build with default parameters")
|
||||
void testDefault() {
|
||||
final A actual = baseBuilder().build();
|
||||
|
||||
verifyAB(actual, null, 0);
|
||||
}
|
||||
|
||||
private void verifyAB(A actual, String a, int b) {
|
||||
assertThat(actual.getA()).isEqualTo(a);
|
||||
assertThat(actual.getB()).isEqualTo(b);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("chain with clause and add new parameters")
|
||||
void testBaseChain() {
|
||||
final A actual = baseBuilder().with(a -> a.a = "hello").build();
|
||||
|
||||
verifyAB(actual, "hello", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("chain multiple with clauses and add new parameters")
|
||||
void testMultiChain() {
|
||||
final A actual = baseBuilder().with(a -> a.a = "world").with(a -> a.b = 6).build();
|
||||
|
||||
verifyAB(actual, "world", 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("chain multiple with clauses and override latest writes")
|
||||
void testMultiChainOverride() {
|
||||
final A actual = baseBuilder().with(a -> a.a = "world").with(a -> a.b = 4).with(a -> a.a = "foobar").build();
|
||||
|
||||
verifyAB(actual, "foobar", 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("not mutate the state of previous builder in the chain")
|
||||
void testImmutability() {
|
||||
final ABuilder builder1 = baseBuilder().with(a -> a.a = "world");
|
||||
final ABuilder builder2 = builder1.with(a -> {
|
||||
a.a = "hello";
|
||||
a.b = 42;
|
||||
});
|
||||
|
||||
verifyAB(builder1.build(), "world", 0);
|
||||
verifyAB(builder2.build(), "hello", 42);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("produce different objects")
|
||||
void differentObjects() {
|
||||
final ABuilder builder = baseBuilder().with(a -> {
|
||||
a.a = "hello";
|
||||
a.b = 42;
|
||||
});
|
||||
final A a1 = builder.build();
|
||||
final A a2 = builder.build();
|
||||
|
||||
assertThat(a1).isNotSameAs(a2);
|
||||
verifyAB(a1, "hello", 42);
|
||||
verifyAB(a2, "hello", 42);
|
||||
}
|
||||
|
||||
static class A {
|
||||
public final String a;
|
||||
private int b;
|
||||
|
||||
public A(String a) {
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
public String getA() {
|
||||
return a;
|
||||
}
|
||||
|
||||
public int getB() {
|
||||
return b;
|
||||
}
|
||||
|
||||
public void setB(int b) {
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
|
||||
static class ABuilder extends FluentBuilder<A, ABuilder> {
|
||||
public String a;
|
||||
public int b;
|
||||
|
||||
private ABuilder() {
|
||||
super(ABuilder::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected A makeValue() {
|
||||
final A result = new A(a);
|
||||
result.setB(b);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package mage.player.ai;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.SpellAbility;
|
||||
|
@ -29,6 +30,7 @@ import mage.player.ai.util.CombatInfo;
|
|||
import mage.player.ai.util.CombatUtil;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetAmount;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.Targets;
|
||||
import mage.util.RandomUtil;
|
||||
|
@ -37,6 +39,7 @@ import org.apache.log4j.Logger;
|
|||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author nantuko
|
||||
|
@ -155,7 +158,13 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
boolean usedStack = false;
|
||||
while (actions.peek() != null) {
|
||||
Ability ability = actions.poll();
|
||||
logger.info(new StringBuilder("===> Act [").append(game.getPlayer(playerId).getName()).append("] Action: ").append(ability.toString()).toString());
|
||||
// log example: ===> Act [PlayerA] Action: Cast Blessings of Nature (target 1; target 2)
|
||||
logger.info(new StringBuilder("===> Act [")
|
||||
.append(game.getPlayer(playerId).getName())
|
||||
.append("] Action: ")
|
||||
.append(ability.toString())
|
||||
.append(listTargets(game, ability.getTargets(), " (targeting %s)", ""))
|
||||
.toString());
|
||||
if (!ability.getTargets().isEmpty()) {
|
||||
for (Target target : ability.getTargets()) {
|
||||
for (UUID id : target.getTargets()) {
|
||||
|
@ -506,7 +515,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
StringBuilder sb = new StringBuilder("Sim Prio [").append(depth).append("] #").append(counter)
|
||||
.append(" <").append(val).append("> (").append(action)
|
||||
.append(action.isModal() ? " Mode = " + action.getModes().getMode().toString() : "")
|
||||
.append(listTargets(game, action.getTargets())).append(')')
|
||||
.append(listTargets(game, action.getTargets(), " (targeting %s)", "")).append(')')
|
||||
.append(logger.isTraceEnabled() ? " #" + newNode.hashCode() : "");
|
||||
SimulationNode2 logNode = newNode;
|
||||
while (logNode.getChildren() != null
|
||||
|
@ -541,7 +550,11 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
if (depth == maxDepth) {
|
||||
GameStateEvaluator2.PlayerEvaluateScore score = GameStateEvaluator2.evaluate(this.getId(), bestNode.game);
|
||||
String scoreInfo = " [" + score.getPlayerInfoShort() + "-" + score.getOpponentInfoShort() + "]";
|
||||
logger.info("Sim Prio [" + depth + "] -- Saved best node yet <" + bestNode.getScore() + scoreInfo + "> " + bestNode.getAbilities().toString());
|
||||
String abilitiesInfo = bestNode.getAbilities()
|
||||
.stream()
|
||||
.map(a -> a.toString() + listTargets(game, a.getTargets(), " (targeting %s)", ""))
|
||||
.collect(Collectors.joining("; "));
|
||||
logger.info("Sim Prio [" + depth + "] -- Saved best node yet <" + bestNode.getScore() + scoreInfo + "> " + abilitiesInfo);
|
||||
node.children.clear();
|
||||
node.children.add(bestNode);
|
||||
node.setScore(bestNode.getScore());
|
||||
|
@ -1009,17 +1022,36 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
|
|||
return suggestedActions.size();
|
||||
}
|
||||
|
||||
protected String listTargets(Game game, Targets targets) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (targets != null) {
|
||||
for (Target target : targets) {
|
||||
sb.append('[').append(target.getTargetedName(game)).append(']');
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
sb.insert(0, " targeting ");
|
||||
/**
|
||||
* Return info about targets list (targeting objects)
|
||||
*
|
||||
* @param game
|
||||
* @param targets
|
||||
* @param format example: my %s in data
|
||||
* @param emptyText default text for empty targets list
|
||||
* @return
|
||||
*/
|
||||
protected String listTargets(Game game, Targets targets, String format, String emptyText) {
|
||||
List<String> res = new ArrayList<>();
|
||||
for (Target target : targets) {
|
||||
for (UUID id : target.getTargets()) {
|
||||
MageObject object = game.getObject(id);
|
||||
if (object != null) {
|
||||
String prefix = "";
|
||||
if (target instanceof TargetAmount) {
|
||||
prefix = " " + target.getTargetAmount(id) + "x ";
|
||||
}
|
||||
res.add(prefix + object.getIdName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
String info = String.join("; ", res);
|
||||
|
||||
if (info.isEmpty()) {
|
||||
return emptyText;
|
||||
} else {
|
||||
return String.format(format, info);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1130,7 +1130,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
}
|
||||
|
||||
log.warn("No proper AI target handling: " + target.getClass().getName());
|
||||
// it's ok on no targets available
|
||||
log.warn("No proper AI target handling or can't find permanents/cards to target: " + target.getClass().getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -238,7 +238,7 @@
|
|||
<dependency>
|
||||
<groupId>com.google.api-client</groupId>
|
||||
<artifactId>google-api-client</artifactId>
|
||||
<version>1.30.10</version>
|
||||
<version>1.31.1</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -256,7 +256,7 @@
|
|||
<dependency>
|
||||
<groupId>com.google.oauth-client</groupId>
|
||||
<artifactId>google-oauth-client-jetty</artifactId>
|
||||
<version>1.31.0</version>
|
||||
<version>1.31.2</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -285,6 +285,18 @@
|
|||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.32.3.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -358,6 +370,10 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<finalName>mage-server</finalName>
|
||||
|
|
|
@ -5,8 +5,8 @@ import mage.cards.repository.CardRepository;
|
|||
import mage.game.Game;
|
||||
import mage.server.exceptions.UserNotFoundException;
|
||||
import mage.server.game.GameController;
|
||||
import mage.server.game.GameManager;
|
||||
import mage.server.game.GamesRoomManager;
|
||||
import mage.server.managers.ChatManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.server.util.SystemUtil;
|
||||
import mage.view.ChatMessage.MessageColor;
|
||||
import mage.view.ChatMessage.MessageType;
|
||||
|
@ -26,21 +26,27 @@ import java.util.stream.Collectors;
|
|||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum ChatManager {
|
||||
public class ChatManagerImpl implements ChatManager {
|
||||
|
||||
instance;
|
||||
private static final Logger logger = Logger.getLogger(ChatManager.class);
|
||||
private static final Logger logger = Logger.getLogger(ChatManagerImpl.class);
|
||||
private static final HashMap<String, String> userMessages = new HashMap<>();
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final ConcurrentHashMap<UUID, ChatSession> chatSessions = new ConcurrentHashMap<>();
|
||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
public ChatManagerImpl(ManagerFactory managerFactory) {
|
||||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID createChatSession(String info) {
|
||||
ChatSession chatSession = new ChatSession(info);
|
||||
ChatSession chatSession = new ChatSession(managerFactory, info);
|
||||
chatSessions.put(chatSession.getChatId(), chatSession);
|
||||
return chatSession.getChatId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void joinChat(UUID chatId, UUID userId) {
|
||||
ChatSession chatSession = chatSessions.get(chatId);
|
||||
if (chatSession != null) {
|
||||
|
@ -51,10 +57,12 @@ public enum ChatManager {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearUserMessageStorage() {
|
||||
userMessages.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveChat(UUID chatId, UUID userId) {
|
||||
ChatSession chatSession = chatSessions.get(chatId);
|
||||
if (chatSession != null && chatSession.hasUser(userId)) {
|
||||
|
@ -62,6 +70,7 @@ public enum ChatManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyChatSession(UUID chatId) {
|
||||
if (chatId != null) {
|
||||
ChatSession chatSession = chatSessions.get(chatId);
|
||||
|
@ -84,11 +93,12 @@ public enum ChatManager {
|
|||
|
||||
final Pattern cardNamePattern = Pattern.compile("\\[(.*?)\\]");
|
||||
|
||||
@Override
|
||||
public void broadcast(UUID chatId, String userName, String message, MessageColor color, boolean withTime, Game game, MessageType messageType, SoundToPlay soundToPlay) {
|
||||
ChatSession chatSession = chatSessions.get(chatId);
|
||||
if (chatSession != null) {
|
||||
if (message.startsWith("\\") || message.startsWith("/")) {
|
||||
Optional<User> user = UserManager.instance.getUserByName(userName);
|
||||
Optional<User> user = managerFactory.userManager().getUserByName(userName);
|
||||
if (user.isPresent()) {
|
||||
if (!performUserCommand(user.get(), message, chatId, false)) {
|
||||
performUserCommand(user.get(), message, chatId, true);
|
||||
|
@ -98,7 +108,7 @@ public enum ChatManager {
|
|||
}
|
||||
|
||||
if (messageType != MessageType.GAME && !userName.isEmpty()) {
|
||||
Optional<User> u = UserManager.instance.getUserByName(userName);
|
||||
Optional<User> u = managerFactory.userManager().getUserByName(userName);
|
||||
if (u.isPresent()) {
|
||||
|
||||
User user = u.get();
|
||||
|
@ -184,12 +194,12 @@ public enum ChatManager {
|
|||
}
|
||||
|
||||
if (command.startsWith("H ") || command.startsWith("HISTORY ")) {
|
||||
message += "<br/>" + UserManager.instance.getUserHistory(message.substring(command.startsWith("H ") ? 3 : 9));
|
||||
message += "<br/>" + managerFactory.userManager().getUserHistory(message.substring(command.startsWith("H ") ? 3 : 9));
|
||||
chatSessions.get(chatId).broadcastInfoToUser(user, message);
|
||||
return true;
|
||||
}
|
||||
if (command.equals("ME")) {
|
||||
message += "<br/>" + UserManager.instance.getUserHistory(user.getName());
|
||||
message += "<br/>" + managerFactory.userManager().getUserHistory(user.getName());
|
||||
chatSessions.get(chatId).broadcastInfoToUser(user, message);
|
||||
return true;
|
||||
}
|
||||
|
@ -200,7 +210,7 @@ public enum ChatManager {
|
|||
String gameId = session.getInfo();
|
||||
if (gameId.startsWith("Game ")) {
|
||||
UUID id = java.util.UUID.fromString(gameId.substring(5));
|
||||
for (Entry<UUID, GameController> entry : GameManager.instance.getGameController().entrySet()) {
|
||||
for (Entry<UUID, GameController> entry : managerFactory.gameManager().getGameController().entrySet()) {
|
||||
if (entry.getKey().equals(id)) {
|
||||
GameController controller = entry.getValue();
|
||||
if (controller != null) {
|
||||
|
@ -221,7 +231,7 @@ public enum ChatManager {
|
|||
String gameId = session.getInfo();
|
||||
if (gameId.startsWith("Game ")) {
|
||||
UUID id = java.util.UUID.fromString(gameId.substring(5));
|
||||
for (Entry<UUID, GameController> entry : GameManager.instance.getGameController().entrySet()) {
|
||||
for (Entry<UUID, GameController> entry : managerFactory.gameManager().getGameController().entrySet()) {
|
||||
if (entry.getKey().equals(id)) {
|
||||
GameController controller = entry.getValue();
|
||||
if (controller != null) {
|
||||
|
@ -242,7 +252,7 @@ public enum ChatManager {
|
|||
String gameId = session.getInfo();
|
||||
if (gameId.startsWith("Game ")) {
|
||||
UUID id = java.util.UUID.fromString(gameId.substring(5));
|
||||
for (Entry<UUID, GameController> entry : GameManager.instance.getGameController().entrySet()) {
|
||||
for (Entry<UUID, GameController> entry : managerFactory.gameManager().getGameController().entrySet()) {
|
||||
if (entry.getKey().equals(id)) {
|
||||
GameController controller = entry.getValue();
|
||||
if (controller != null) {
|
||||
|
@ -281,7 +291,7 @@ public enum ChatManager {
|
|||
if (first > 1) {
|
||||
String userToName = rest.substring(0, first);
|
||||
rest = rest.substring(first + 1).trim();
|
||||
Optional<User> userTo = UserManager.instance.getUserByName(userToName);
|
||||
Optional<User> userTo = managerFactory.userManager().getUserByName(userToName);
|
||||
if (userTo.isPresent()) {
|
||||
if (!chatSessions.get(chatId).broadcastWhisperToUser(user, userTo.get(), rest)) {
|
||||
message += new StringBuilder("<br/>User ").append(userToName).append(" not found").toString();
|
||||
|
@ -312,8 +322,9 @@ public enum ChatManager {
|
|||
* @param color
|
||||
* @throws mage.server.exceptions.UserNotFoundException
|
||||
*/
|
||||
@Override
|
||||
public void broadcast(UUID userId, String message, MessageColor color) throws UserNotFoundException {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
getChatSessions()
|
||||
.stream()
|
||||
.filter(chat -> chat.hasUser(userId))
|
||||
|
@ -322,8 +333,9 @@ public enum ChatManager {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendReconnectMessage(UUID userId) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user
|
||||
-> getChatSessions()
|
||||
.stream()
|
||||
.filter(chat -> chat.hasUser(userId))
|
||||
|
@ -331,8 +343,9 @@ public enum ChatManager {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLostConnectionMessage(UUID userId, DisconnectReason reason) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> sendMessageToUserChats(userId, user.getName() + " " + reason.getMessage()));
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> sendMessageToUserChats(userId, user.getName() + " " + reason.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -341,10 +354,11 @@ public enum ChatManager {
|
|||
* @param userId
|
||||
* @param message
|
||||
*/
|
||||
@Override
|
||||
public void sendMessageToUserChats(UUID userId, String message) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
List<ChatSession> chatSessions = getChatSessions().stream()
|
||||
.filter(chat -> !chat.getChatId().equals(GamesRoomManager.instance.getMainChatId())) // ignore main lobby
|
||||
.filter(chat -> !chat.getChatId().equals(managerFactory.gamesRoomManager().getMainChatId())) // ignore main lobby
|
||||
.filter(chat -> chat.hasUser(userId))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
@ -355,6 +369,7 @@ public enum ChatManager {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUser(UUID userId, DisconnectReason reason) {
|
||||
for (ChatSession chatSession : getChatSessions()) {
|
||||
if (chatSession.hasUser(userId)) {
|
||||
|
@ -363,6 +378,7 @@ public enum ChatManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChatSession> getChatSessions() {
|
||||
final Lock r = lock.readLock();
|
||||
r.lock();
|
|
@ -3,6 +3,7 @@ package mage.server;
|
|||
import mage.game.Game;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.interfaces.callback.ClientCallbackMethod;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.view.ChatMessage;
|
||||
import mage.view.ChatMessage.MessageColor;
|
||||
import mage.view.ChatMessage.MessageType;
|
||||
|
@ -25,6 +26,7 @@ public class ChatSession {
|
|||
private static final Logger logger = Logger.getLogger(ChatSession.class);
|
||||
private static final DateFormat timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT);
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
private final ConcurrentMap<UUID, String> clients = new ConcurrentHashMap<>();
|
||||
|
@ -32,14 +34,15 @@ public class ChatSession {
|
|||
private final Date createTime;
|
||||
private final String info;
|
||||
|
||||
public ChatSession(String info) {
|
||||
public ChatSession(ManagerFactory managerFactory, String info) {
|
||||
this.managerFactory = managerFactory;
|
||||
chatId = UUID.randomUUID();
|
||||
this.createTime = new Date();
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public void join(UUID userId) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
if (!clients.containsKey(userId)) {
|
||||
String userName = user.getName();
|
||||
final Lock w = lock.writeLock();
|
||||
|
@ -121,7 +124,7 @@ public class ChatSession {
|
|||
r.unlock();
|
||||
}
|
||||
for (UUID userId : chatUserIds) {
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
if (user.isPresent()) {
|
||||
user.get().fireCallback(clientCallback);
|
||||
} else {
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
package mage.server;
|
||||
|
||||
import com.google.api.client.auth.oauth2.Credential;
|
||||
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
|
||||
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
|
||||
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.json.JsonFactory;
|
||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||
import com.google.api.client.util.Base64;
|
||||
import com.google.api.client.util.store.FileDataStoreFactory;
|
||||
import com.google.api.services.gmail.Gmail;
|
||||
import com.google.api.services.gmail.Gmail.Builder;
|
||||
import com.google.api.services.gmail.GmailScopes;
|
||||
import com.google.api.services.gmail.model.Message;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Collections;
|
||||
import java.util.Properties;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import mage.server.util.ConfigSettings;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public final class GmailClient {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Main.class);
|
||||
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
|
||||
private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".store/xmage");
|
||||
private static FileDataStoreFactory dataStoreFactory;
|
||||
private static HttpTransport httpTransport;
|
||||
private static Credential credential;
|
||||
|
||||
public static boolean initilize() {
|
||||
try {
|
||||
dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
|
||||
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
|
||||
|
||||
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new FileReader("client_secrets.json"));
|
||||
if (clientSecrets.getDetails().getClientId().startsWith("Enter")
|
||||
|| clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
|
||||
logger.error("client_secrets.json not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
|
||||
httpTransport, JSON_FACTORY, clientSecrets,
|
||||
Collections.singleton(GmailScopes.GMAIL_COMPOSE)).setDataStoreFactory(
|
||||
dataStoreFactory).build();
|
||||
|
||||
credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
|
||||
return true;
|
||||
} catch (IOException | GeneralSecurityException ex) {
|
||||
logger.error("Error initializing GmailClient", ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean sendMessage(String email, String subject, String text) {
|
||||
if (email.isEmpty()) {
|
||||
logger.info("Email is not sent because the address is empty");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Gmail gmail = new Builder(httpTransport, JSON_FACTORY, credential).setApplicationName("XMage Server").build();
|
||||
|
||||
MimeMessage mimeMessage = new MimeMessage(Session.getDefaultInstance(new Properties()));
|
||||
mimeMessage.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(email));
|
||||
mimeMessage.setSubject(subject);
|
||||
mimeMessage.setText(text);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
mimeMessage.writeTo(baos);
|
||||
Message message = new Message();
|
||||
message.setRaw(Base64.encodeBase64URLSafeString(baos.toByteArray()));
|
||||
|
||||
gmail.users().messages().send(ConfigSettings.instance.getGoogleAccount()
|
||||
+ (ConfigSettings.instance.getGoogleAccount().endsWith("@gmail.com") ? "" : "@gmail.com"), message).execute();
|
||||
return true;
|
||||
} catch (MessagingException | IOException ex) {
|
||||
logger.error("Error sending message", ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -23,15 +23,14 @@ import mage.players.PlayerType;
|
|||
import mage.players.net.UserData;
|
||||
import mage.remote.MageVersionException;
|
||||
import mage.server.draft.CubeFactory;
|
||||
import mage.server.draft.DraftManager;
|
||||
import mage.server.game.*;
|
||||
import mage.server.game.GameFactory;
|
||||
import mage.server.game.GamesRoom;
|
||||
import mage.server.game.PlayerFactory;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.server.services.impl.FeedbackServiceImpl;
|
||||
import mage.server.tournament.TournamentFactory;
|
||||
import mage.server.tournament.TournamentManager;
|
||||
import mage.server.util.ConfigSettings;
|
||||
import mage.server.util.ServerMessagesUtil;
|
||||
import mage.server.util.SystemUtil;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
import mage.utils.*;
|
||||
import mage.view.*;
|
||||
import mage.view.ChatMessage.MessageColor;
|
||||
|
@ -49,9 +48,10 @@ import java.util.concurrent.ExecutorService;
|
|||
public class MageServerImpl implements MageServer {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MageServerImpl.class);
|
||||
private static final ExecutorService callExecutor = ThreadExecutor.instance.getCallExecutor();
|
||||
private final ExecutorService callExecutor;
|
||||
private static final SecureRandom RANDOM = new SecureRandom();
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final String adminPassword;
|
||||
private final boolean testMode;
|
||||
private final LinkedHashMap<String, String> activeAuthTokens = new LinkedHashMap<String, String>() {
|
||||
|
@ -62,15 +62,17 @@ public class MageServerImpl implements MageServer {
|
|||
}
|
||||
};
|
||||
|
||||
public MageServerImpl(String adminPassword, boolean testMode) {
|
||||
public MageServerImpl(ManagerFactory managerFactory, String adminPassword, boolean testMode) {
|
||||
this.managerFactory = managerFactory;
|
||||
this.adminPassword = adminPassword;
|
||||
this.testMode = testMode;
|
||||
this.callExecutor = managerFactory.threadExecutor().getCallExecutor();
|
||||
ServerMessagesUtil.instance.getMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerUser(String sessionId, String userName, String password, String email) throws MageException {
|
||||
return SessionManager.instance.registerUser(sessionId, userName, password, email);
|
||||
return managerFactory.sessionManager().registerUser(sessionId, userName, password, email);
|
||||
}
|
||||
|
||||
// generateAuthToken returns a uniformly distributed 6-digits string.
|
||||
|
@ -80,7 +82,7 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
public boolean emailAuthToken(String sessionId, String email) throws MageException {
|
||||
if (!ConfigSettings.instance.isAuthenticationActivated()) {
|
||||
if (!managerFactory.configSettings().isAuthenticationActivated()) {
|
||||
sendErrorMessageToClient(sessionId, "Registration is disabled by the server config");
|
||||
return false;
|
||||
}
|
||||
|
@ -96,10 +98,10 @@ public class MageServerImpl implements MageServer {
|
|||
String text = "Use this auth token to reset " + authorizedUser.name + "'s password: " + authToken + '\n'
|
||||
+ "It's valid until the next server restart.";
|
||||
boolean success;
|
||||
if (!ConfigSettings.instance.getMailUser().isEmpty()) {
|
||||
success = MailClient.sendMessage(email, subject, text);
|
||||
if (!managerFactory.configSettings().getMailUser().isEmpty()) {
|
||||
success = managerFactory.mailClient().sendMessage(email, subject, text);
|
||||
} else {
|
||||
success = MailgunClient.sendMessage(email, subject, text);
|
||||
success = managerFactory.mailgunClient().sendMessage(email, subject, text);
|
||||
}
|
||||
if (!success) {
|
||||
sendErrorMessageToClient(sessionId, "There was an error inside the server while emailing an auth token");
|
||||
|
@ -110,7 +112,7 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
public boolean resetPassword(String sessionId, String email, String authToken, String password) throws MageException {
|
||||
if (!ConfigSettings.instance.isAuthenticationActivated()) {
|
||||
if (!managerFactory.configSettings().isAuthenticationActivated()) {
|
||||
sendErrorMessageToClient(sessionId, "Registration is disabled by the server config");
|
||||
return false;
|
||||
}
|
||||
|
@ -139,7 +141,7 @@ public class MageServerImpl implements MageServer {
|
|||
logger.info("MageVersionException: userName=" + userName + ", version=" + version + " sessionId=" + sessionId);
|
||||
throw new MageVersionException(version, Main.getVersion());
|
||||
}
|
||||
return SessionManager.instance.connectUser(sessionId, userName, password, userIdStr);
|
||||
return managerFactory.sessionManager().connectUser(sessionId, userName, password, userIdStr);
|
||||
} catch (MageException ex) {
|
||||
if (ex instanceof MageVersionException) {
|
||||
throw ex;
|
||||
|
@ -154,7 +156,7 @@ public class MageServerImpl implements MageServer {
|
|||
return executeWithResult("setUserData", sessionId, new ActionWithBooleanResult() {
|
||||
@Override
|
||||
public Boolean execute() throws MageException {
|
||||
return SessionManager.instance.setUserData(userName, sessionId, userData, clientVersion, userIdStr);
|
||||
return managerFactory.sessionManager().setUserData(userName, sessionId, userData, clientVersion, userIdStr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -168,7 +170,7 @@ public class MageServerImpl implements MageServer {
|
|||
if (!adminPassword.equals(this.adminPassword)) {
|
||||
throw new MageException("Wrong password");
|
||||
}
|
||||
return SessionManager.instance.connectAdmin(sessionId);
|
||||
return managerFactory.sessionManager().connectAdmin(sessionId);
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
|
@ -186,13 +188,13 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public TableView execute() throws MageException {
|
||||
try {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session to found : " + sessionId);
|
||||
return null;
|
||||
}
|
||||
UUID userId = session.get().getUserId();
|
||||
Optional<User> _user = UserManager.instance.getUser(userId);
|
||||
Optional<User> _user = managerFactory.userManager().getUser(userId);
|
||||
if (!_user.isPresent()) {
|
||||
logger.error("User for session not found. session = " + sessionId);
|
||||
return null;
|
||||
|
@ -205,7 +207,7 @@ public class MageServerImpl implements MageServer {
|
|||
throw new MageException("No message");
|
||||
}
|
||||
// check AI players max
|
||||
String maxAiOpponents = ConfigSettings.instance.getMaxAiOpponents();
|
||||
String maxAiOpponents = managerFactory.configSettings().getMaxAiOpponents();
|
||||
if (maxAiOpponents != null) {
|
||||
int aiPlayers = 0;
|
||||
for (PlayerType playerType : options.getPlayerTypes()) {
|
||||
|
@ -241,7 +243,7 @@ public class MageServerImpl implements MageServer {
|
|||
user.showUserMessage("Create tournament", message);
|
||||
throw new MageException("No message");
|
||||
}
|
||||
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
|
||||
Optional<GamesRoom> room = managerFactory.gamesRoomManager().getRoom(roomId);
|
||||
if (!room.isPresent()) {
|
||||
|
||||
} else {
|
||||
|
@ -260,9 +262,9 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void removeTable(final String sessionId, final UUID roomId, final UUID tableId) throws MageException {
|
||||
execute("removeTable", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
TableManager.instance.removeTable(userId, tableId);
|
||||
managerFactory.tableManager().removeTable(userId, tableId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -272,7 +274,7 @@ public class MageServerImpl implements MageServer {
|
|||
return executeWithResult("joinTable", sessionId, new ActionWithBooleanResult() {
|
||||
@Override
|
||||
public Boolean execute() throws MageException {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -282,7 +284,7 @@ public class MageServerImpl implements MageServer {
|
|||
logger.fatal("Got no userId from sessionId" + sessionId + " tableId" + tableId);
|
||||
return false;
|
||||
}
|
||||
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
|
||||
Optional<GamesRoom> room = managerFactory.gamesRoomManager().getRoom(roomId);
|
||||
if (!room.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -297,20 +299,20 @@ public class MageServerImpl implements MageServer {
|
|||
return executeWithResult("joinTournamentTable", sessionId, new ActionWithBooleanResult() {
|
||||
@Override
|
||||
public Boolean execute() throws MageException {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
UUID userId = session.get().getUserId();
|
||||
if (logger.isTraceEnabled()) {
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
user.ifPresent(user1 -> logger.trace("join tourn. tableId: " + tableId + ' ' + name));
|
||||
}
|
||||
if (userId == null) {
|
||||
logger.fatal("Got no userId from sessionId" + sessionId + " tableId" + tableId);
|
||||
return false;
|
||||
}
|
||||
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
|
||||
Optional<GamesRoom> room = managerFactory.gamesRoomManager().getRoom(roomId);
|
||||
if (room.isPresent()) {
|
||||
return room.get().joinTournamentTable(userId, tableId, name, playerType, skill, deckList, password);
|
||||
}
|
||||
|
@ -325,12 +327,12 @@ public class MageServerImpl implements MageServer {
|
|||
return executeWithResult("submitDeck", sessionId, new ActionWithBooleanResult() {
|
||||
@Override
|
||||
public Boolean execute() throws MageException {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
return false;
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
boolean ret = TableManager.instance.submitDeck(userId, tableId, deckList);
|
||||
boolean ret = managerFactory.tableManager().submitDeck(userId, tableId, deckList);
|
||||
logger.debug("Session " + sessionId + " submitted deck");
|
||||
return ret;
|
||||
}
|
||||
|
@ -341,13 +343,13 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void updateDeck(final String sessionId, final UUID tableId, final DeckCardLists deckList) throws MageException {
|
||||
execute("updateDeck", sessionId, () -> {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
TableManager.instance.updateDeck(userId, tableId, deckList);
|
||||
managerFactory.tableManager().updateDeck(userId, tableId, deckList);
|
||||
logger.trace("Session " + sessionId + " updated deck");
|
||||
}
|
||||
});
|
||||
|
@ -357,7 +359,7 @@ public class MageServerImpl implements MageServer {
|
|||
//FIXME: why no sessionId here???
|
||||
public List<TableView> getTables(UUID roomId) throws MageException {
|
||||
try {
|
||||
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
|
||||
Optional<GamesRoom> room = managerFactory.gamesRoomManager().getRoom(roomId);
|
||||
if (room.isPresent()) {
|
||||
return room.get().getTables();
|
||||
} else {
|
||||
|
@ -373,7 +375,7 @@ public class MageServerImpl implements MageServer {
|
|||
//FIXME: why no sessionId here???
|
||||
public List<MatchView> getFinishedMatches(UUID roomId) throws MageException {
|
||||
try {
|
||||
return GamesRoomManager.instance.getRoom(roomId).map(GamesRoom::getFinished).orElse(new ArrayList<>());
|
||||
return managerFactory.gamesRoomManager().getRoom(roomId).map(GamesRoom::getFinished).orElse(new ArrayList<>());
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
|
@ -383,7 +385,7 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public List<RoomUsersView> getRoomUsers(UUID roomId) throws MageException {
|
||||
try {
|
||||
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
|
||||
Optional<GamesRoom> room = managerFactory.gamesRoomManager().getRoom(roomId);
|
||||
if (room.isPresent()) {
|
||||
return room.get().getRoomUsersInfo();
|
||||
} else {
|
||||
|
@ -399,7 +401,7 @@ public class MageServerImpl implements MageServer {
|
|||
//FIXME: why no sessionId here???
|
||||
public TableView getTable(UUID roomId, UUID tableId) throws MageException {
|
||||
try {
|
||||
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
|
||||
Optional<GamesRoom> room = managerFactory.gamesRoomManager().getRoom(roomId);
|
||||
return room.flatMap(r -> r.getTable(tableId)).orElse(null);
|
||||
|
||||
} catch (Exception ex) {
|
||||
|
@ -410,22 +412,12 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
public boolean ping(String sessionId, String pingInfo) {
|
||||
return SessionManager.instance.extendUserSession(sessionId, pingInfo);
|
||||
return managerFactory.sessionManager().extendUserSession(sessionId, pingInfo);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void deregisterClient(final String sessionId) throws MageException {
|
||||
// execute("deregisterClient", sessionId, new Action() {
|
||||
// @Override
|
||||
// public void execute() {
|
||||
// SessionManager.instance.disconnect(sessionId, true);
|
||||
// logger.debug("Client deregistered ...");
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
@Override
|
||||
public boolean startMatch(final String sessionId, final UUID roomId, final UUID tableId) throws MageException {
|
||||
Optional<TableController> controller = TableManager.instance.getController(tableId);
|
||||
Optional<TableController> controller = managerFactory.tableManager().getController(tableId);
|
||||
if (!controller.isPresent()) {
|
||||
logger.error("table not found : " + tableId);
|
||||
return false;
|
||||
|
@ -434,30 +426,20 @@ public class MageServerImpl implements MageServer {
|
|||
return false;
|
||||
}
|
||||
execute("startMatch", sessionId, () -> {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
TableManager.instance.startMatch(userId, roomId, tableId);
|
||||
managerFactory.tableManager().startMatch(userId, roomId, tableId);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void startChallenge(final String sessionId, final UUID roomId, final UUID tableId, final UUID challengeId) throws MageException {
|
||||
// execute("startChallenge", sessionId, new Action() {
|
||||
// @Override
|
||||
// public void execute() {
|
||||
// UUID userId = SessionManager.instance.getSession(sessionId).getUserId();
|
||||
// TableManager.instance.startChallenge(userId, roomId, tableId, challengeId);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
@Override
|
||||
public boolean startTournament(final String sessionId, final UUID roomId, final UUID tableId) throws MageException {
|
||||
Optional<TableController> controller = TableManager.instance.getController(tableId);
|
||||
Optional<TableController> controller = managerFactory.tableManager().getController(tableId);
|
||||
if (!controller.isPresent()) {
|
||||
logger.error("table not found : " + tableId);
|
||||
return false;
|
||||
|
@ -466,12 +448,12 @@ public class MageServerImpl implements MageServer {
|
|||
return false;
|
||||
}
|
||||
execute("startTournament", sessionId, () -> {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
TableManager.instance.startTournament(userId, roomId, tableId);
|
||||
managerFactory.tableManager().startTournament(userId, roomId, tableId);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
|
@ -481,7 +463,7 @@ public class MageServerImpl implements MageServer {
|
|||
//FIXME: why no sessionId here???
|
||||
public TournamentView getTournament(UUID tournamentId) throws MageException {
|
||||
try {
|
||||
return TournamentManager.instance.getTournamentView(tournamentId);
|
||||
return managerFactory.tournamentManager().getTournamentView(tournamentId);
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
|
@ -493,7 +475,7 @@ public class MageServerImpl implements MageServer {
|
|||
public void sendChatMessage(final UUID chatId, final String userName, final String message) throws MageException {
|
||||
try {
|
||||
callExecutor.execute(
|
||||
() -> ChatManager.instance.broadcast(chatId, userName, StringEscapeUtils.escapeHtml4(message), MessageColor.BLUE, true, null, ChatMessage.MessageType.TALK, null)
|
||||
() -> managerFactory.chatManager().broadcast(chatId, userName, StringEscapeUtils.escapeHtml4(message), MessageColor.BLUE, true, null, ChatMessage.MessageType.TALK, null)
|
||||
);
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
|
@ -503,10 +485,10 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void joinChat(final UUID chatId, final String sessionId, final String userName) throws MageException {
|
||||
execute("joinChat", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
|
||||
UUID userId = session.getUserId();
|
||||
ChatManager.instance.joinChat(chatId, userId);
|
||||
managerFactory.chatManager().joinChat(chatId, userId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -515,9 +497,9 @@ public class MageServerImpl implements MageServer {
|
|||
public void leaveChat(final UUID chatId, final String sessionId) throws MageException {
|
||||
execute("leaveChat", sessionId, () -> {
|
||||
if (chatId != null) {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
ChatManager.instance.leaveChat(chatId, userId);
|
||||
managerFactory.chatManager().leaveChat(chatId, userId);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -527,7 +509,7 @@ public class MageServerImpl implements MageServer {
|
|||
//FIXME: why no sessionId here???
|
||||
public UUID getMainRoomId() throws MageException {
|
||||
try {
|
||||
return GamesRoomManager.instance.getMainRoomId();
|
||||
return managerFactory.gamesRoomManager().getMainRoomId();
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
|
@ -538,7 +520,7 @@ public class MageServerImpl implements MageServer {
|
|||
//FIXME: why no sessionId here???
|
||||
public UUID getRoomChatId(UUID roomId) throws MageException {
|
||||
try {
|
||||
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
|
||||
Optional<GamesRoom> room = managerFactory.gamesRoomManager().getRoom(roomId);
|
||||
if (!room.isPresent()) {
|
||||
logger.error("roomId not found : " + roomId);
|
||||
return null;
|
||||
|
@ -555,12 +537,12 @@ public class MageServerImpl implements MageServer {
|
|||
return executeWithResult("isTableOwner", sessionId, new ActionWithBooleanResult() {
|
||||
@Override
|
||||
public Boolean execute() {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
return false;
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
return TableManager.instance.isTableOwner(tableId, userId);
|
||||
return managerFactory.tableManager().isTableOwner(tableId, userId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -569,16 +551,16 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void swapSeats(final String sessionId, final UUID roomId, final UUID tableId, final int seatNum1, final int seatNum2) throws MageException {
|
||||
execute("swapSeats", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
TableManager.instance.swapSeats(tableId, userId, seatNum1, seatNum2);
|
||||
managerFactory.tableManager().swapSeats(tableId, userId, seatNum1, seatNum2);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean leaveTable(final String sessionId, final UUID roomId, final UUID tableId) throws MageException {
|
||||
Optional<TableController> tableController = TableManager.instance.getController(tableId);
|
||||
Optional<TableController> tableController = managerFactory.tableManager().getController(tableId);
|
||||
if (tableController.isPresent()) {
|
||||
TableState tableState = tableController.get().getTableState();
|
||||
if (tableState != TableState.WAITING && tableState != TableState.READY_TO_START) {
|
||||
|
@ -586,9 +568,9 @@ public class MageServerImpl implements MageServer {
|
|||
return false;
|
||||
}
|
||||
execute("leaveTable", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
GamesRoomManager.instance.getRoom(roomId).ifPresent(room ->
|
||||
managerFactory.gamesRoomManager().getRoom(roomId).ifPresent(room ->
|
||||
room.leaveTable(userId, tableId));
|
||||
|
||||
});
|
||||
|
@ -604,7 +586,7 @@ public class MageServerImpl implements MageServer {
|
|||
//FIXME: why no sessionId here???
|
||||
public UUID getTableChatId(UUID tableId) throws MageException {
|
||||
try {
|
||||
return TableManager.instance.getChatId(tableId).orElse(null);
|
||||
return managerFactory.tableManager().getChatId(tableId).orElse(null);
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
|
@ -614,9 +596,9 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void joinGame(final UUID gameId, final String sessionId) throws MageException {
|
||||
execute("joinGame", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
GameManager.instance.joinGame(gameId, userId);
|
||||
managerFactory.gameManager().joinGame(gameId, userId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -624,9 +606,9 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void joinDraft(final UUID draftId, final String sessionId) throws MageException {
|
||||
execute("joinDraft", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
DraftManager.instance.joinDraft(draftId, userId);
|
||||
managerFactory.draftManager().joinDraft(draftId, userId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -634,12 +616,12 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void joinTournament(final UUID tournamentId, final String sessionId) throws MageException {
|
||||
execute("joinTournament", sessionId, () -> {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
TournamentManager.instance.joinTournament(tournamentId, userId);
|
||||
managerFactory.tournamentManager().joinTournament(tournamentId, userId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -648,7 +630,7 @@ public class MageServerImpl implements MageServer {
|
|||
//FIXME: why no sessionId here???
|
||||
public UUID getGameChatId(UUID gameId) throws MageException {
|
||||
try {
|
||||
return GameManager.instance.getChatId(gameId).orElse(null);
|
||||
return managerFactory.gameManager().getChatId(gameId).orElse(null);
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
|
@ -659,7 +641,7 @@ public class MageServerImpl implements MageServer {
|
|||
//FIXME: why no sessionId here???
|
||||
public UUID getTournamentChatId(UUID tournamentId) throws MageException {
|
||||
try {
|
||||
return TournamentManager.instance.getChatId(tournamentId).orElse(null);
|
||||
return managerFactory.tournamentManager().getChatId(tournamentId).orElse(null);
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
|
@ -669,9 +651,8 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void sendPlayerUUID(final UUID gameId, final String sessionId, final UUID data) throws MageException {
|
||||
execute("sendPlayerUUID", sessionId, () -> {
|
||||
Optional<User> user = SessionManager.instance.getUser(sessionId);
|
||||
Optional<User> user = managerFactory.sessionManager().getUser(sessionId);
|
||||
if (user.isPresent()) {
|
||||
// logger.warn("sendPlayerUUID gameId=" + gameId + " sessionId=" + sessionId + " username=" + user.getName());
|
||||
user.get().sendPlayerUUID(gameId, data);
|
||||
} else {
|
||||
logger.warn("Your session expired: gameId=" + gameId + ", sessionId=" + sessionId);
|
||||
|
@ -682,7 +663,7 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void sendPlayerString(final UUID gameId, final String sessionId, final String data) throws MageException {
|
||||
execute("sendPlayerString", sessionId, () -> {
|
||||
Optional<User> user = SessionManager.instance.getUser(sessionId);
|
||||
Optional<User> user = managerFactory.sessionManager().getUser(sessionId);
|
||||
if (user.isPresent()) {
|
||||
user.get().sendPlayerString(gameId, data);
|
||||
} else {
|
||||
|
@ -694,7 +675,7 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void sendPlayerManaType(final UUID gameId, final UUID playerId, final String sessionId, final ManaType data) throws MageException {
|
||||
execute("sendPlayerManaType", sessionId, () -> {
|
||||
Optional<User> user = SessionManager.instance.getUser(sessionId);
|
||||
Optional<User> user = managerFactory.sessionManager().getUser(sessionId);
|
||||
if (user.isPresent()) {
|
||||
user.get().sendPlayerManaType(gameId, playerId, data);
|
||||
} else {
|
||||
|
@ -706,7 +687,7 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void sendPlayerBoolean(final UUID gameId, final String sessionId, final Boolean data) throws MageException {
|
||||
execute("sendPlayerBoolean", sessionId, () -> {
|
||||
Optional<User> user = SessionManager.instance.getUser(sessionId);
|
||||
Optional<User> user = managerFactory.sessionManager().getUser(sessionId);
|
||||
if (user.isPresent()) {
|
||||
user.get().sendPlayerBoolean(gameId, data);
|
||||
} else {
|
||||
|
@ -718,7 +699,7 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void sendPlayerInteger(final UUID gameId, final String sessionId, final Integer data) throws MageException {
|
||||
execute("sendPlayerInteger", sessionId, () -> {
|
||||
Optional<User> user = SessionManager.instance.getUser(sessionId);
|
||||
Optional<User> user = managerFactory.sessionManager().getUser(sessionId);
|
||||
if (user.isPresent()) {
|
||||
user.get().sendPlayerInteger(gameId, data);
|
||||
} else {
|
||||
|
@ -735,9 +716,9 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void sendCardMark(final UUID draftId, final String sessionId, final UUID cardPick) throws MageException {
|
||||
execute("sendCardMark", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
DraftManager.instance.sendCardMark(draftId, userId, cardPick);
|
||||
managerFactory.draftManager().sendCardMark(draftId, userId, cardPick);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -748,9 +729,9 @@ public class MageServerImpl implements MageServer {
|
|||
try {
|
||||
callExecutor.execute(
|
||||
() -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
GameManager.instance.quitMatch(gameId, userId);
|
||||
managerFactory.gameManager().quitMatch(gameId, userId);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -766,10 +747,10 @@ public class MageServerImpl implements MageServer {
|
|||
try {
|
||||
callExecutor.execute(
|
||||
() -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
|
||||
TournamentManager.instance.quit(tournamentId, userId);
|
||||
managerFactory.tournamentManager().quit(tournamentId, userId);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -786,14 +767,14 @@ public class MageServerImpl implements MageServer {
|
|||
try {
|
||||
callExecutor.execute(
|
||||
() -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(
|
||||
session -> {
|
||||
UUID userId = session.getUserId();
|
||||
UUID tableId = DraftManager.instance.getControllerByDraftId(draftId).getTableId();
|
||||
Table table = TableManager.instance.getTable(tableId);
|
||||
UUID tableId = managerFactory.draftManager().getControllerByDraftId(draftId).getTableId();
|
||||
Table table = managerFactory.tableManager().getTable(tableId);
|
||||
if (table.isTournament()) {
|
||||
UUID tournamentId = table.getTournament().getId();
|
||||
TournamentManager.instance.quit(tournamentId, userId);
|
||||
managerFactory.tournamentManager().quit(tournamentId, userId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -808,9 +789,9 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void sendPlayerAction(final PlayerAction playerAction, final UUID gameId, final String sessionId, final Object data) throws MageException {
|
||||
execute("sendPlayerAction", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
GameManager.instance.sendPlayerAction(playerAction, gameId, userId, data);
|
||||
managerFactory.gameManager().sendPlayerAction(playerAction, gameId, userId, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -820,14 +801,14 @@ public class MageServerImpl implements MageServer {
|
|||
return executeWithResult("setUserData", sessionId, new ActionWithBooleanResult() {
|
||||
@Override
|
||||
public Boolean execute() throws MageException {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
return false;
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
if (GamesRoomManager.instance.getRoom(roomId).isPresent()) {
|
||||
return GamesRoomManager.instance.getRoom(roomId).get().watchTable(userId, tableId);
|
||||
if (managerFactory.gamesRoomManager().getRoom(roomId).isPresent()) {
|
||||
return managerFactory.gamesRoomManager().getRoom(roomId).get().watchTable(userId, tableId);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -846,10 +827,10 @@ public class MageServerImpl implements MageServer {
|
|||
return executeWithResult("watchGame", sessionId, new ActionWithResult<Boolean>() {
|
||||
@Override
|
||||
public Boolean execute() throws MageException {
|
||||
return SessionManager.instance.getSession(sessionId)
|
||||
return managerFactory.sessionManager().getSession(sessionId)
|
||||
.map(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
return GameManager.instance.watchGame(gameId, userId);
|
||||
return managerFactory.gameManager().watchGame(gameId, userId);
|
||||
}).orElse(false);
|
||||
}
|
||||
|
||||
|
@ -863,10 +844,10 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void stopWatching(final UUID gameId, final String sessionId) throws MageException {
|
||||
execute("stopWatching", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
GameManager.instance.stopWatching(gameId, userId);
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
managerFactory.gameManager().stopWatching(gameId, userId);
|
||||
user.removeGameWatchInfo(gameId);
|
||||
});
|
||||
});
|
||||
|
@ -877,9 +858,9 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void replayGame(final UUID gameId, final String sessionId) throws MageException {
|
||||
execute("replayGame", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
ReplayManager.instance.replayGame(gameId, userId);
|
||||
managerFactory.replayManager().replayGame(gameId, userId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -887,9 +868,9 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void startReplay(final UUID gameId, final String sessionId) throws MageException {
|
||||
execute("startReplay", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
ReplayManager.instance.startReplay(gameId, userId);
|
||||
managerFactory.replayManager().startReplay(gameId, userId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -897,12 +878,12 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void stopReplay(final UUID gameId, final String sessionId) throws MageException {
|
||||
execute("stopReplay", sessionId, () -> {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
ReplayManager.instance.stopReplay(gameId, userId);
|
||||
managerFactory.replayManager().stopReplay(gameId, userId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -910,12 +891,12 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void nextPlay(final UUID gameId, final String sessionId) throws MageException {
|
||||
execute("nextPlay", sessionId, () -> {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
ReplayManager.instance.nextPlay(gameId, userId);
|
||||
managerFactory.replayManager().nextPlay(gameId, userId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -923,12 +904,12 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void previousPlay(final UUID gameId, final String sessionId) throws MageException {
|
||||
execute("previousPlay", sessionId, () -> {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
ReplayManager.instance.previousPlay(gameId, userId);
|
||||
managerFactory.replayManager().previousPlay(gameId, userId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -936,12 +917,12 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void skipForward(final UUID gameId, final String sessionId, final int moves) throws MageException {
|
||||
execute("skipForward", sessionId, () -> {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
ReplayManager.instance.skipForward(gameId, userId, moves);
|
||||
managerFactory.replayManager().skipForward(gameId, userId, moves);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -971,9 +952,9 @@ public class MageServerImpl implements MageServer {
|
|||
public void cheat(final UUID gameId, final String sessionId, final UUID playerId, final DeckCardLists deckList) throws MageException {
|
||||
execute("cheat", sessionId, () -> {
|
||||
if (testMode) {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
GameManager.instance.cheat(gameId, userId, playerId, deckList);
|
||||
managerFactory.gameManager().cheat(gameId, userId, playerId, deckList);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -985,12 +966,12 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public Boolean execute() {
|
||||
if (testMode) {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
return GameManager.instance.cheat(gameId, userId, playerId, cardName);
|
||||
return managerFactory.gameManager().cheat(gameId, userId, playerId, cardName);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -1024,13 +1005,13 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
public void disconnectUser(final String sessionId, final String userSessionId) throws MageException {
|
||||
execute("disconnectUser", sessionId, () -> SessionManager.instance.disconnectUser(sessionId, userSessionId));
|
||||
execute("disconnectUser", sessionId, () -> managerFactory.sessionManager().disconnectUser(sessionId, userSessionId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void muteUser(final String sessionId, final String userName, final long durationMinutes) throws MageException {
|
||||
execute("muteUser", sessionId, () -> {
|
||||
UserManager.instance.getUserByName(userName).ifPresent(user -> {
|
||||
managerFactory.userManager().getUserByName(userName).ifPresent(user -> {
|
||||
Date muteUntil = new Date(Calendar.getInstance().getTimeInMillis() + (durationMinutes * Timer.ONE_MINUTE));
|
||||
user.showUserMessage("Admin info", "You were muted for chat messages until " + SystemUtil.dateFormat.format(muteUntil) + '.');
|
||||
user.setChatLockedUntil(muteUntil);
|
||||
|
@ -1042,12 +1023,12 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void lockUser(final String sessionId, final String userName, final long durationMinutes) throws MageException {
|
||||
execute("lockUser", sessionId, () -> {
|
||||
UserManager.instance.getUserByName(userName).ifPresent(user -> {
|
||||
managerFactory.userManager().getUserByName(userName).ifPresent(user -> {
|
||||
Date lockUntil = new Date(Calendar.getInstance().getTimeInMillis() + (durationMinutes * Timer.ONE_MINUTE));
|
||||
user.showUserMessage("Admin info", "Your user profile was locked until " + SystemUtil.dateFormat.format(lockUntil) + '.');
|
||||
user.setLockedUntil(lockUntil);
|
||||
if (user.isConnected()) {
|
||||
SessionManager.instance.disconnectUser(sessionId, user.getSessionId());
|
||||
managerFactory.sessionManager().disconnectUser(sessionId, user.getSessionId());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1058,15 +1039,15 @@ public class MageServerImpl implements MageServer {
|
|||
public void setActivation(final String sessionId, final String userName, boolean active) throws MageException {
|
||||
execute("setActivation", sessionId, () -> {
|
||||
AuthorizedUser authorizedUser = AuthorizedUserRepository.instance.getByName(userName);
|
||||
Optional<User> u = UserManager.instance.getUserByName(userName);
|
||||
Optional<User> u = managerFactory.userManager().getUserByName(userName);
|
||||
if (u.isPresent()) {
|
||||
User user = u.get();
|
||||
user.setActive(active);
|
||||
if (!user.isActive() && user.isConnected()) {
|
||||
SessionManager.instance.disconnectUser(sessionId, user.getSessionId());
|
||||
managerFactory.sessionManager().disconnectUser(sessionId, user.getSessionId());
|
||||
}
|
||||
} else if (authorizedUser != null) {
|
||||
User theUser = new User(userName, "localhost", authorizedUser);
|
||||
User theUser = new User(managerFactory, userName, "localhost", authorizedUser);
|
||||
theUser.setActive(active);
|
||||
}
|
||||
|
||||
|
@ -1076,18 +1057,18 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void toggleActivation(final String sessionId, final String userName) throws MageException {
|
||||
execute("toggleActivation", sessionId, ()
|
||||
-> UserManager.instance.getUserByName(userName).ifPresent(user
|
||||
-> managerFactory.userManager().getUserByName(userName).ifPresent(user
|
||||
-> {
|
||||
user.setActive(!user.isActive());
|
||||
if (!user.isActive() && user.isConnected()) {
|
||||
SessionManager.instance.disconnectUser(sessionId, user.getSessionId());
|
||||
managerFactory.sessionManager().disconnectUser(sessionId, user.getSessionId());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endUserSession(final String sessionId, final String userSessionId) throws MageException {
|
||||
execute("endUserSession", sessionId, () -> SessionManager.instance.endUserSession(sessionId, userSessionId));
|
||||
execute("endUserSession", sessionId, () -> managerFactory.sessionManager().endUserSession(sessionId, userSessionId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1100,9 +1081,9 @@ public class MageServerImpl implements MageServer {
|
|||
@Override
|
||||
public void removeTable(final String sessionId, final UUID tableId) throws MageException {
|
||||
execute("removeTable", sessionId, () -> {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session -> {
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> {
|
||||
UUID userId = session.getUserId();
|
||||
TableManager.instance.removeTable(userId, tableId);
|
||||
managerFactory.tableManager().removeTable(userId, tableId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1116,7 +1097,7 @@ public class MageServerImpl implements MageServer {
|
|||
public void sendFeedbackMessage(final String sessionId, final String username, final String title, final String type, final String message, final String email) throws MageException {
|
||||
if (title != null && message != null) {
|
||||
execute("sendFeedbackMessage", sessionId, ()
|
||||
-> SessionManager.instance.getSession(sessionId).ifPresent(
|
||||
-> managerFactory.sessionManager().getSession(sessionId).ifPresent(
|
||||
session -> FeedbackServiceImpl.instance.feedback(username, title, type, message, email, session.getHost())
|
||||
));
|
||||
}
|
||||
|
@ -1126,7 +1107,7 @@ public class MageServerImpl implements MageServer {
|
|||
public void sendBroadcastMessage(final String sessionId, final String message) throws MageException {
|
||||
if (message != null) {
|
||||
execute("sendBroadcastMessage", sessionId, () -> {
|
||||
for (User user : UserManager.instance.getUsers()) {
|
||||
for (User user : managerFactory.userManager().getUsers()) {
|
||||
if (message.toLowerCase(Locale.ENGLISH).startsWith("warn")) {
|
||||
user.fireCallback(new ClientCallback(ClientCallbackMethod.SERVER_MESSAGE, null, new ChatMessage("SERVER", message, null, null, MessageColor.RED)));
|
||||
} else {
|
||||
|
@ -1138,12 +1119,12 @@ public class MageServerImpl implements MageServer {
|
|||
}
|
||||
|
||||
private void sendErrorMessageToClient(final String sessionId, final String message) throws MageException {
|
||||
execute("sendErrorMessageToClient", sessionId, () -> SessionManager.instance.sendErrorMessageToClient(sessionId, message));
|
||||
execute("sendErrorMessageToClient", sessionId, () -> managerFactory.sessionManager().sendErrorMessageToClient(sessionId, message));
|
||||
}
|
||||
|
||||
protected void execute(final String actionName, final String sessionId, final Action action, boolean checkAdminRights) throws MageException {
|
||||
if (checkAdminRights) {
|
||||
if (!SessionManager.instance.isAdmin(sessionId)) {
|
||||
if (!managerFactory.sessionManager().isAdmin(sessionId)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1151,11 +1132,11 @@ public class MageServerImpl implements MageServer {
|
|||
}
|
||||
|
||||
protected void execute(final String actionName, final String sessionId, final Action action) throws MageException {
|
||||
if (SessionManager.instance.isValidSession(sessionId)) {
|
||||
if (managerFactory.sessionManager().isValidSession(sessionId)) {
|
||||
try {
|
||||
callExecutor.execute(
|
||||
() -> {
|
||||
if (SessionManager.instance.isValidSession(sessionId)) {
|
||||
if (managerFactory.sessionManager().isValidSession(sessionId)) {
|
||||
try {
|
||||
action.execute();
|
||||
} catch (MageException me) {
|
||||
|
@ -1172,7 +1153,7 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
protected <T> T executeWithResult(String actionName, final String sessionId, final ActionWithResult<T> action, boolean checkAdminRights) throws MageException {
|
||||
if (checkAdminRights) {
|
||||
if (!SessionManager.instance.isAdmin(sessionId)) {
|
||||
if (!managerFactory.sessionManager().isAdmin(sessionId)) {
|
||||
return action.negativeResult();
|
||||
}
|
||||
}
|
||||
|
@ -1181,7 +1162,7 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
//TODO: also run in threads with future task
|
||||
protected <T> T executeWithResult(String actionName, final String sessionId, final ActionWithResult<T> action) throws MageException {
|
||||
if (SessionManager.instance.isValidSession(sessionId)) {
|
||||
if (managerFactory.sessionManager().isValidSession(sessionId)) {
|
||||
try {
|
||||
return action.execute();
|
||||
} catch (Exception ex) {
|
||||
|
@ -1218,15 +1199,15 @@ public class MageServerImpl implements MageServer {
|
|||
}
|
||||
}
|
||||
|
||||
private static class ListActionWithNullNegativeResult extends ActionWithNullNegativeResult<List<UserView>> {
|
||||
private class ListActionWithNullNegativeResult extends ActionWithNullNegativeResult<List<UserView>> {
|
||||
|
||||
@Override
|
||||
public List<UserView> execute() throws MageException {
|
||||
return UserManager.instance.getUserInfoList();
|
||||
return managerFactory.userManager().getUserInfoList();
|
||||
}
|
||||
}
|
||||
|
||||
private static class GameViewActionWithNullNegativeResult extends ActionWithNullNegativeResult<GameView> {
|
||||
private class GameViewActionWithNullNegativeResult extends ActionWithNullNegativeResult<GameView> {
|
||||
|
||||
private final String sessionId;
|
||||
private final UUID gameId;
|
||||
|
@ -1240,18 +1221,18 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
public GameView execute() throws MageException {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
return null;
|
||||
} else {
|
||||
//UUID userId = session.get().getUserId();
|
||||
return GameManager.instance.getGameView(gameId, playerId);
|
||||
return managerFactory.gameManager().getGameView(gameId, playerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyActionWithBooleanResult extends ActionWithBooleanResult {
|
||||
private class MyActionWithBooleanResult extends ActionWithBooleanResult {
|
||||
|
||||
private final String sessionId;
|
||||
private final UUID tableId;
|
||||
|
@ -1263,17 +1244,17 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
public Boolean execute() throws MageException {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
return false;
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
return TableManager.instance.watchTable(userId, tableId);
|
||||
return managerFactory.tableManager().watchTable(userId, tableId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class DraftPickViewActionWithNullNegativeResult extends ActionWithNullNegativeResult<DraftPickView> {
|
||||
private class DraftPickViewActionWithNullNegativeResult extends ActionWithNullNegativeResult<DraftPickView> {
|
||||
|
||||
private final String sessionId;
|
||||
private final UUID draftId;
|
||||
|
@ -1289,9 +1270,9 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
public DraftPickView execute() {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (session.isPresent()) {
|
||||
return DraftManager.instance.sendCardPick(draftId, session.get().getUserId(), cardPick, hiddenCards);
|
||||
return managerFactory.draftManager().sendCardPick(draftId, session.get().getUserId(), cardPick, hiddenCards);
|
||||
} else {
|
||||
logger.error("Session not found sessionId: " + sessionId + " draftId:" + draftId);
|
||||
}
|
||||
|
@ -1299,7 +1280,7 @@ public class MageServerImpl implements MageServer {
|
|||
}
|
||||
}
|
||||
|
||||
private static class MyActionWithTableViewResult extends ActionWithTableViewResult {
|
||||
private class MyActionWithTableViewResult extends ActionWithTableViewResult {
|
||||
|
||||
private final String sessionId;
|
||||
private final MatchOptions options;
|
||||
|
@ -1313,12 +1294,12 @@ public class MageServerImpl implements MageServer {
|
|||
|
||||
@Override
|
||||
public TableView execute() throws MageException {
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
return null;
|
||||
}
|
||||
UUID userId = session.get().getUserId();
|
||||
Optional<User> _user = UserManager.instance.getUser(userId);
|
||||
Optional<User> _user = managerFactory.userManager().getUser(userId);
|
||||
if (!_user.isPresent()) {
|
||||
logger.error("User for session not found. session = " + sessionId);
|
||||
return null;
|
||||
|
@ -1349,13 +1330,13 @@ public class MageServerImpl implements MageServer {
|
|||
user.showUserMessage("Create table", message);
|
||||
throw new MageException("No message");
|
||||
}
|
||||
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(roomId);
|
||||
Optional<GamesRoom> room = managerFactory.gamesRoomManager().getRoom(roomId);
|
||||
if (room.isPresent()) {
|
||||
TableView table = room.get().createTable(userId, options);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("TABLE created - tableId: " + table.getTableId() + ' ' + table.getTableName());
|
||||
logger.debug("- " + user.getName() + " userId: " + user.getId());
|
||||
logger.debug("- chatId: " + TableManager.instance.getChatId(table.getTableId()));
|
||||
logger.debug("- chatId: " + managerFactory.tableManager().getChatId(table.getTableId()));
|
||||
}
|
||||
return table;
|
||||
} else {
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
package mage.server;
|
||||
|
||||
import java.util.Properties;
|
||||
import mage.server.managers.ConfigSettings;
|
||||
import mage.server.managers.MailClient;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import mage.server.util.ConfigSettings;
|
||||
import org.apache.log4j.Logger;
|
||||
import java.util.Properties;
|
||||
|
||||
public final class MailClient {
|
||||
public class MailClientImpl implements MailClient {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Main.class);
|
||||
|
||||
public static boolean sendMessage(String email, String subject, String text) {
|
||||
private final ConfigSettings config;
|
||||
|
||||
public MailClientImpl(ConfigSettings config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public boolean sendMessage(String email, String subject, String text) {
|
||||
if (email.isEmpty()) {
|
||||
logger.info("Email is not sent because the address is empty");
|
||||
return false;
|
||||
}
|
||||
ConfigSettings config = ConfigSettings.instance;
|
||||
|
||||
Properties properties = System.getProperties();
|
||||
properties.setProperty("mail.smtps.host", config.getMailSmtpHost());
|
||||
|
@ -30,7 +37,7 @@ public final class MailClient {
|
|||
|
||||
Session session = Session.getDefaultInstance(properties);
|
||||
|
||||
try{
|
||||
try {
|
||||
MimeMessage message = new MimeMessage(session);
|
||||
message.setFrom(new InternetAddress(config.getMailFromAddress()));
|
||||
message.addRecipient(Message.RecipientType.TO, new InternetAddress(email));
|
||||
|
@ -44,7 +51,7 @@ public final class MailClient {
|
|||
trnsport.close();
|
||||
|
||||
return true;
|
||||
}catch (MessagingException ex) {
|
||||
} catch (MessagingException ex) {
|
||||
logger.error("Error sending message to " + email, ex);
|
||||
}
|
||||
return false;
|
|
@ -5,29 +5,37 @@ import com.sun.jersey.api.client.ClientResponse;
|
|||
import com.sun.jersey.api.client.WebResource;
|
||||
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
|
||||
import com.sun.jersey.core.util.MultivaluedMapImpl;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import mage.server.util.ConfigSettings;
|
||||
import mage.server.managers.ConfigSettings;
|
||||
import mage.server.managers.MailClient;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public final class MailgunClient {
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
public class MailgunClientImpl implements MailClient {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Main.class);
|
||||
|
||||
public static boolean sendMessage(String email, String subject, String text) {
|
||||
private final ConfigSettings config;
|
||||
|
||||
public MailgunClientImpl(ConfigSettings config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public boolean sendMessage(String email, String subject, String text) {
|
||||
if (email.isEmpty()) {
|
||||
logger.info("Email is not sent because the address is empty");
|
||||
return false;
|
||||
}
|
||||
Client client = Client.create();
|
||||
client.addFilter(new HTTPBasicAuthFilter("api", ConfigSettings.instance.getMailgunApiKey()));
|
||||
String domain = ConfigSettings.instance.getMailgunDomain();
|
||||
client.addFilter(new HTTPBasicAuthFilter("api", config.getMailgunApiKey()));
|
||||
String domain = config.getMailgunDomain();
|
||||
WebResource webResource = client.resource("https://api.mailgun.net/v3/" + domain + "/messages");
|
||||
MultivaluedMapImpl formData = new MultivaluedMapImpl();
|
||||
formData.add("from", "XMage <postmaster@" + domain + '>');
|
||||
formData.add("to", email);
|
||||
formData.add("subject", subject);
|
||||
formData.add("text", text);
|
||||
ClientResponse response = webResource.type(MediaType.APPLICATION_FORM_URLENCODED).post(ClientResponse.class, formData);
|
||||
ClientResponse response = webResource.type(MediaType.APPLICATION_FORM_URLENCODED).post(ClientResponse.class, formData);
|
||||
boolean succeeded = response.getStatus() == 200;
|
||||
if (!succeeded) {
|
||||
logger.error("Error sending message to " + email + ". Status code: " + response.getStatus());
|
|
@ -14,12 +14,11 @@ import mage.remote.Connection;
|
|||
import mage.server.draft.CubeFactory;
|
||||
import mage.server.game.GameFactory;
|
||||
import mage.server.game.PlayerFactory;
|
||||
import mage.server.managers.ConfigSettings;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.server.record.UserStatsRepository;
|
||||
import mage.server.tournament.TournamentFactory;
|
||||
import mage.server.util.ConfigSettings;
|
||||
import mage.server.util.PluginClassLoader;
|
||||
import mage.server.util.ServerMessagesUtil;
|
||||
import mage.server.util.SystemUtil;
|
||||
import mage.server.util.*;
|
||||
import mage.server.util.config.GamePlugin;
|
||||
import mage.server.util.config.Plugin;
|
||||
import mage.utils.MageVersion;
|
||||
|
@ -40,6 +39,7 @@ import java.io.IOException;
|
|||
import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
|
@ -53,9 +53,16 @@ public final class Main {
|
|||
private static final String testModeArg = "-testMode=";
|
||||
private static final String fastDBModeArg = "-fastDbMode=";
|
||||
private static final String adminPasswordArg = "-adminPassword=";
|
||||
/**
|
||||
* The property that holds the path to the configuration file. Defaults to "config/config.xml".
|
||||
*
|
||||
* To set up a different one, start the application with the java option "-Dxmage.config.path=<path>"
|
||||
*/
|
||||
private static final String configPathProp = "xmage.config.path";
|
||||
|
||||
private static final File pluginFolder = new File("plugins");
|
||||
private static final File extensionFolder = new File("extensions");
|
||||
private static final String defaultConfigPath = Paths.get("config", "config.xml").toString();
|
||||
|
||||
public static final PluginClassLoader classLoader = new PluginClassLoader();
|
||||
private static TransporterServer server;
|
||||
|
@ -70,7 +77,6 @@ public final class Main {
|
|||
logger.info("Starting MAGE server version " + version);
|
||||
logger.info("Logging level: " + logger.getEffectiveLevel());
|
||||
logger.info("Default charset: " + Charset.defaultCharset());
|
||||
|
||||
String adminPassword = "";
|
||||
for (String arg : args) {
|
||||
if (arg.startsWith(testModeArg)) {
|
||||
|
@ -83,7 +89,14 @@ public final class Main {
|
|||
}
|
||||
}
|
||||
|
||||
if (ConfigSettings.instance.isAuthenticationActivated()) {
|
||||
final String configPath = Optional.ofNullable(System.getProperty(configPathProp))
|
||||
.orElse(defaultConfigPath);
|
||||
|
||||
logger.info(String.format("Reading configuration from path=%s", configPath));
|
||||
final ConfigWrapper config = new ConfigWrapper(ConfigFactory.loadFromFile(configPath));
|
||||
|
||||
|
||||
if (config.isAuthenticationActivated()) {
|
||||
logger.info("Check authorized user DB version ...");
|
||||
if (!AuthorizedUserRepository.instance.checkAlterAndMigrateAuthorizedUser()) {
|
||||
logger.fatal("Failed to start server.");
|
||||
|
@ -148,7 +161,6 @@ public final class Main {
|
|||
UserStatsRepository.instance.updateUserStats();
|
||||
logger.info("Done.");
|
||||
deleteSavedGames();
|
||||
ConfigSettings config = ConfigSettings.instance;
|
||||
for (GamePlugin plugin : config.getGameTypes()) {
|
||||
GameFactory.instance.addGameType(plugin.getName(), loadGameType(plugin), loadPlugin(plugin));
|
||||
}
|
||||
|
@ -206,11 +218,12 @@ public final class Main {
|
|||
Connection connection = new Connection("&maxPoolSize=" + config.getMaxPoolSize());
|
||||
connection.setHost(config.getServerAddress());
|
||||
connection.setPort(config.getPort());
|
||||
final ManagerFactory managerFactory = new MainManagerFactory(config);
|
||||
try {
|
||||
// Parameter: serializationtype => jboss
|
||||
InvokerLocator serverLocator = new InvokerLocator(connection.getURI());
|
||||
if (!isAlreadyRunning(serverLocator)) {
|
||||
server = new MageTransporterServer(serverLocator, new MageServerImpl(adminPassword, testMode), MageServer.class.getName(), new MageServerInvocationHandler());
|
||||
if (!isAlreadyRunning(config, serverLocator)) {
|
||||
server = new MageTransporterServer(managerFactory, serverLocator, new MageServerImpl(managerFactory, adminPassword, testMode), MageServer.class.getName(), new MageServerInvocationHandler(managerFactory));
|
||||
server.start();
|
||||
logger.info("Started MAGE server - listening on " + connection.toString());
|
||||
|
||||
|
@ -230,9 +243,9 @@ public final class Main {
|
|||
ServerMessagesUtil.instance.setStartDate(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
static boolean isAlreadyRunning(InvokerLocator serverLocator) {
|
||||
static boolean isAlreadyRunning(ConfigSettings config, InvokerLocator serverLocator) {
|
||||
Map<String, String> metadata = new HashMap<>();
|
||||
metadata.put(SocketWrapper.WRITE_TIMEOUT, String.valueOf(ConfigSettings.instance.getSocketWriteTimeout()));
|
||||
metadata.put(SocketWrapper.WRITE_TIMEOUT, String.valueOf(config.getSocketWriteTimeout()));
|
||||
metadata.put("generalizeSocketException", "true");
|
||||
try {
|
||||
MageServer testServer = (MageServer) TransporterClient.createTransporterClient(serverLocator.getLocatorURI(), MageServer.class, metadata);
|
||||
|
@ -248,16 +261,22 @@ public final class Main {
|
|||
|
||||
static class ClientConnectionListener implements ConnectionListener {
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
|
||||
public ClientConnectionListener(ManagerFactory managerFactory) {
|
||||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleConnectionException(Throwable throwable, Client client) {
|
||||
String sessionId = client.getSessionId();
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.trace("Session not found : " + sessionId);
|
||||
} else {
|
||||
UUID userId = session.get().getUserId();
|
||||
StringBuilder sessionInfo = new StringBuilder();
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
if (user.isPresent()) {
|
||||
sessionInfo.append(user.get().getName()).append(" [").append(user.get().getGameInfo()).append(']');
|
||||
} else {
|
||||
|
@ -267,12 +286,12 @@ public final class Main {
|
|||
if (throwable instanceof ClientDisconnectedException) {
|
||||
// Seems like the random diconnects from public server land here and should not be handled as explicit disconnects
|
||||
// So it should be possible to reconnect to server and continue games if DisconnectReason is set to LostConnection
|
||||
//SessionManager.instance.disconnect(client.getSessionId(), DisconnectReason.Disconnected);
|
||||
SessionManager.instance.disconnect(client.getSessionId(), DisconnectReason.LostConnection);
|
||||
//managerFactory.sessionManager().disconnect(client.getSessionId(), DisconnectReason.Disconnected);
|
||||
managerFactory.sessionManager().disconnect(client.getSessionId(), DisconnectReason.LostConnection);
|
||||
logger.info("CLIENT DISCONNECTED - " + sessionInfo);
|
||||
logger.debug("Stack Trace", throwable);
|
||||
} else {
|
||||
SessionManager.instance.disconnect(client.getSessionId(), DisconnectReason.LostConnection);
|
||||
managerFactory.sessionManager().disconnect(client.getSessionId(), DisconnectReason.LostConnection);
|
||||
logger.info("LOST CONNECTION - " + sessionInfo);
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (throwable == null) {
|
||||
|
@ -292,11 +311,11 @@ public final class Main {
|
|||
|
||||
protected Connector connector;
|
||||
|
||||
public MageTransporterServer(InvokerLocator locator, Object target, String subsystem, MageServerInvocationHandler serverInvocationHandler) throws Exception {
|
||||
public MageTransporterServer(ManagerFactory managerFactory, InvokerLocator locator, Object target, String subsystem, MageServerInvocationHandler serverInvocationHandler) throws Exception {
|
||||
super(locator, target, subsystem);
|
||||
connector.addInvocationHandler("callback", serverInvocationHandler);
|
||||
connector.setLeasePeriod(ConfigSettings.instance.getLeasePeriod());
|
||||
connector.addConnectionListener(new ClientConnectionListener());
|
||||
connector.setLeasePeriod(managerFactory.configSettings().getLeasePeriod());
|
||||
connector.addConnectionListener(new ClientConnectionListener(managerFactory));
|
||||
}
|
||||
|
||||
public Connector getConnector() throws Exception {
|
||||
|
@ -313,6 +332,12 @@ public final class Main {
|
|||
|
||||
static class MageServerInvocationHandler implements ServerInvocationHandler {
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
|
||||
public MageServerInvocationHandler(ManagerFactory managerFactory) {
|
||||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMBeanServer(MBeanServer server) {
|
||||
/**
|
||||
|
@ -333,9 +358,9 @@ public final class Main {
|
|||
|
||||
@Override
|
||||
public void setInvoker(ServerInvoker invoker) {
|
||||
((BisocketServerInvoker) invoker).setSecondaryBindPort(ConfigSettings.instance.getSecondaryBindPort());
|
||||
((BisocketServerInvoker) invoker).setBacklog(ConfigSettings.instance.getBacklogSize());
|
||||
((BisocketServerInvoker) invoker).setNumAcceptThreads(ConfigSettings.instance.getNumAcceptThreads());
|
||||
((BisocketServerInvoker) invoker).setSecondaryBindPort(managerFactory.configSettings().getSecondaryBindPort());
|
||||
((BisocketServerInvoker) invoker).setBacklog(managerFactory.configSettings().getBacklogSize());
|
||||
((BisocketServerInvoker) invoker).setNumAcceptThreads(managerFactory.configSettings().getNumAcceptThreads());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -344,7 +369,7 @@ public final class Main {
|
|||
ServerInvokerCallbackHandler handler = (ServerInvokerCallbackHandler) callbackHandler;
|
||||
try {
|
||||
String sessionId = handler.getClientSessionId();
|
||||
SessionManager.instance.createSession(sessionId, callbackHandler);
|
||||
managerFactory.sessionManager().createSession(sessionId, callbackHandler);
|
||||
} catch (Throwable ex) {
|
||||
logger.fatal("", ex);
|
||||
}
|
||||
|
@ -362,7 +387,7 @@ public final class Main {
|
|||
} else {
|
||||
host = "localhost";
|
||||
}
|
||||
Optional<Session> session = SessionManager.instance.getSession(sessionId);
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(sessionId);
|
||||
if (!session.isPresent()) {
|
||||
logger.error("Session not found : " + sessionId);
|
||||
} else {
|
||||
|
@ -375,7 +400,7 @@ public final class Main {
|
|||
public void removeListener(InvokerCallbackHandler callbackHandler) {
|
||||
ServerInvokerCallbackHandler handler = (ServerInvokerCallbackHandler) callbackHandler;
|
||||
String sessionId = handler.getClientSessionId();
|
||||
SessionManager.instance.disconnect(sessionId, DisconnectReason.Disconnected);
|
||||
managerFactory.sessionManager().disconnect(sessionId, DisconnectReason.Disconnected);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
124
Mage.Server/src/main/java/mage/server/MainManagerFactory.java
Normal file
124
Mage.Server/src/main/java/mage/server/MainManagerFactory.java
Normal file
|
@ -0,0 +1,124 @@
|
|||
package mage.server;
|
||||
|
||||
import mage.server.draft.DraftManagerImpl;
|
||||
import mage.server.game.GameManagerImpl;
|
||||
import mage.server.game.GamesRoomManagerImpl;
|
||||
import mage.server.game.ReplayManagerImpl;
|
||||
import mage.server.managers.*;
|
||||
import mage.server.tournament.TournamentManagerImpl;
|
||||
import mage.server.util.ThreadExecutorImpl;
|
||||
|
||||
public class MainManagerFactory implements ManagerFactory {
|
||||
|
||||
private final ConfigSettings configSettings;
|
||||
private final ThreadExecutor threadExecutor;
|
||||
private final ChatManager chatManager;
|
||||
private final DraftManager draftManager;
|
||||
private final GameManager gameManager;
|
||||
private final GamesRoomManager gamesRoomManager;
|
||||
private final MailClient mailClient;
|
||||
private final MailClient mailgunClient;
|
||||
private final ReplayManager replayManager;
|
||||
private final SessionManager sessionManager;
|
||||
private final TableManager tableManager;
|
||||
private final UserManager userManager;
|
||||
private final TournamentManager tournamentManager;
|
||||
|
||||
|
||||
public MainManagerFactory(ConfigSettings configSettings) {
|
||||
this.configSettings = configSettings;
|
||||
// ThreadExecutorImpl, MailClientImpl and MailGunClient depend only on the config, so they are initialised first
|
||||
this.threadExecutor = new ThreadExecutorImpl(configSettings);
|
||||
this.mailClient = new MailClientImpl(configSettings);
|
||||
this.mailgunClient = new MailgunClientImpl(configSettings);
|
||||
// Chat, Draft, Game, Replay, Session and Tournament managers only require access to the ManagerFactory
|
||||
// but do not use them in initialisation
|
||||
this.chatManager = new ChatManagerImpl(this);
|
||||
this.draftManager = new DraftManagerImpl(this);
|
||||
this.gameManager = new GameManagerImpl(this);
|
||||
this.replayManager = new ReplayManagerImpl(this);
|
||||
this.sessionManager = new SessionManagerImpl(this);
|
||||
this.tournamentManager = new TournamentManagerImpl(this);
|
||||
// GamesRoom, Table, User managers depend on the ManagerFactory and have an initialisation block which is delayed
|
||||
// to the end of the construction
|
||||
final GamesRoomManagerImpl gamesRoomManager = new GamesRoomManagerImpl(this);
|
||||
final TableManagerImpl tableManager = new TableManagerImpl(this);
|
||||
final UserManagerImpl userManager = new UserManagerImpl(this);
|
||||
this.gamesRoomManager = gamesRoomManager;
|
||||
this.tableManager = tableManager;
|
||||
this.userManager = userManager;
|
||||
// execute the initialisation block of the relevant manager (they start the executor services)
|
||||
startThreads(gamesRoomManager, tableManager, userManager);
|
||||
}
|
||||
|
||||
private void startThreads(GamesRoomManagerImpl gamesRoomManager, TableManagerImpl tableManager, UserManagerImpl userManager) {
|
||||
userManager.init();
|
||||
tableManager.init();
|
||||
gamesRoomManager.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatManager chatManager() {
|
||||
return chatManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DraftManager draftManager() {
|
||||
return draftManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameManager gameManager() {
|
||||
return gameManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GamesRoomManager gamesRoomManager() {
|
||||
return gamesRoomManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailClient mailClient() {
|
||||
return mailClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailClient mailgunClient() {
|
||||
return mailgunClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplayManager replayManager() {
|
||||
return replayManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionManager sessionManager() {
|
||||
return sessionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableManager tableManager() {
|
||||
return tableManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserManager userManager() {
|
||||
return userManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigSettings configSettings() {
|
||||
return configSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreadExecutor threadExecutor() {
|
||||
return threadExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TournamentManager tournamentManager() {
|
||||
return tournamentManager;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
|
||||
|
||||
package mage.server;
|
||||
|
||||
import mage.server.managers.ChatManager;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public abstract class RoomImpl implements Room {
|
||||
|
@ -13,9 +12,9 @@ public abstract class RoomImpl implements Room {
|
|||
private final UUID chatId;
|
||||
private final UUID roomId;
|
||||
|
||||
public RoomImpl() {
|
||||
public RoomImpl(ChatManager chatManager) {
|
||||
roomId = UUID.randomUUID();
|
||||
chatId = ChatManager.instance.createChatSession("Room " + roomId);
|
||||
chatId = chatManager.createChatSession("Room " + roomId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,5 +34,4 @@ public abstract class RoomImpl implements Room {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import mage.interfaces.callback.ClientCallbackMethod;
|
|||
import mage.players.net.UserData;
|
||||
import mage.players.net.UserGroup;
|
||||
import mage.server.game.GamesRoom;
|
||||
import mage.server.game.GamesRoomManager;
|
||||
import mage.server.util.ConfigSettings;
|
||||
import mage.server.managers.ConfigSettings;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.server.util.SystemUtil;
|
||||
import mage.util.RandomUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
@ -34,6 +34,7 @@ public class Session {
|
|||
private static final Pattern alphabetsPattern = Pattern.compile("[a-zA-Z]");
|
||||
private static final Pattern digitsPattern = Pattern.compile("[0-9]");
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final String sessionId;
|
||||
private UUID userId;
|
||||
private String host;
|
||||
|
@ -46,7 +47,8 @@ public class Session {
|
|||
private final ReentrantLock lock;
|
||||
private final ReentrantLock callBackLock;
|
||||
|
||||
public Session(String sessionId, InvokerCallbackHandler callbackHandler) {
|
||||
public Session(ManagerFactory managerFactory, String sessionId, InvokerCallbackHandler callbackHandler) {
|
||||
this.managerFactory = managerFactory;
|
||||
this.sessionId = sessionId;
|
||||
this.callbackHandler = (AsynchInvokerCallbackHandler) callbackHandler;
|
||||
this.isAdmin = false;
|
||||
|
@ -56,7 +58,7 @@ public class Session {
|
|||
}
|
||||
|
||||
public String registerUser(String userName, String password, String email) throws MageException {
|
||||
if (!ConfigSettings.instance.isAuthenticationActivated()) {
|
||||
if (!managerFactory.configSettings().isAuthenticationActivated()) {
|
||||
String returnMessage = "Registration is disabled by the server config";
|
||||
sendErrorMessageToClient(returnMessage);
|
||||
return returnMessage;
|
||||
|
@ -86,10 +88,10 @@ public class Session {
|
|||
|
||||
boolean success;
|
||||
String subject = "XMage Registration Completed";
|
||||
if (!ConfigSettings.instance.getMailUser().isEmpty()) {
|
||||
success = MailClient.sendMessage(email, subject, text);
|
||||
if (!managerFactory.configSettings().getMailUser().isEmpty()) {
|
||||
success = managerFactory.mailClient().sendMessage(email, subject, text);
|
||||
} else {
|
||||
success = MailgunClient.sendMessage(email, subject, text);
|
||||
success = managerFactory.mailgunClient().sendMessage(email, subject, text);
|
||||
}
|
||||
if (success) {
|
||||
String ok = "Sent a registration confirmation / initial password email to " + email + " for " + userName;
|
||||
|
@ -109,18 +111,18 @@ public class Session {
|
|||
}
|
||||
}
|
||||
|
||||
private static String validateUserName(String userName) {
|
||||
private String validateUserName(String userName) {
|
||||
if (userName.equals("Admin")) {
|
||||
return "User name Admin already in use";
|
||||
}
|
||||
ConfigSettings config = ConfigSettings.instance;
|
||||
ConfigSettings config = managerFactory.configSettings();
|
||||
if (userName.length() < config.getMinUserNameLength()) {
|
||||
return "User name may not be shorter than " + config.getMinUserNameLength() + " characters";
|
||||
}
|
||||
if (userName.length() > config.getMaxUserNameLength()) {
|
||||
return "User name may not be longer than " + config.getMaxUserNameLength() + " characters";
|
||||
}
|
||||
Pattern invalidUserNamePattern = Pattern.compile(ConfigSettings.instance.getInvalidUserNamePattern(), Pattern.CASE_INSENSITIVE);
|
||||
Pattern invalidUserNamePattern = Pattern.compile(managerFactory.configSettings().getInvalidUserNamePattern(), Pattern.CASE_INSENSITIVE);
|
||||
Matcher m = invalidUserNamePattern.matcher(userName);
|
||||
if (m.find()) {
|
||||
return "User name '" + userName + "' includes not allowed characters: use a-z, A-Z and 0-9";
|
||||
|
@ -132,8 +134,8 @@ public class Session {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static String validatePassword(String password, String userName) {
|
||||
ConfigSettings config = ConfigSettings.instance;
|
||||
private String validatePassword(String password, String userName) {
|
||||
ConfigSettings config = managerFactory.configSettings();
|
||||
if (password.length() < config.getMinPasswordLength()) {
|
||||
return "Password may not be shorter than " + config.getMinPasswordLength() + " characters";
|
||||
}
|
||||
|
@ -178,7 +180,7 @@ public class Session {
|
|||
public String connectUserHandling(String userName, String password) throws MageException {
|
||||
this.isAdmin = false;
|
||||
AuthorizedUser authorizedUser = null;
|
||||
if (ConfigSettings.instance.isAuthenticationActivated()) {
|
||||
if (managerFactory.configSettings().isAuthenticationActivated()) {
|
||||
authorizedUser = AuthorizedUserRepository.instance.getByName(userName);
|
||||
String errorMsg = "Wrong username or password. In case you haven't, please register your account first.";
|
||||
if (authorizedUser == null) {
|
||||
|
@ -196,7 +198,7 @@ public class Session {
|
|||
if (authorizedUser.lockedUntil.compareTo(Calendar.getInstance().getTime()) > 0) {
|
||||
return "Your profile is deactivated until " + SystemUtil.dateFormat.format(authorizedUser.lockedUntil);
|
||||
} else {
|
||||
UserManager.instance.createUser(userName, host, authorizedUser).ifPresent(user
|
||||
managerFactory.userManager().createUser(userName, host, authorizedUser).ifPresent(user
|
||||
-> user.setLockedUntil(null)
|
||||
);
|
||||
|
||||
|
@ -204,15 +206,15 @@ public class Session {
|
|||
}
|
||||
}
|
||||
|
||||
Optional<User> selectUser = UserManager.instance.createUser(userName, host, authorizedUser);
|
||||
Optional<User> selectUser = managerFactory.userManager().createUser(userName, host, authorizedUser);
|
||||
boolean reconnect = false;
|
||||
if (!selectUser.isPresent()) {
|
||||
// user already connected
|
||||
selectUser = UserManager.instance.getUserByName(userName);
|
||||
selectUser = managerFactory.userManager().getUserByName(userName);
|
||||
if (selectUser.isPresent()) {
|
||||
User user = selectUser.get();
|
||||
// If authentication is not activated, check the identity using IP address.
|
||||
if (ConfigSettings.instance.isAuthenticationActivated() || user.getHost().equals(host)) {
|
||||
if (managerFactory.configSettings().isAuthenticationActivated() || user.getHost().equals(host)) {
|
||||
user.updateLastActivity(null); // minimizes possible expiration
|
||||
this.userId = user.getId();
|
||||
if (user.getSessionId().isEmpty()) {
|
||||
|
@ -221,7 +223,7 @@ public class Session {
|
|||
} else {
|
||||
//disconnect previous session
|
||||
logger.info("Disconnecting another user instance: " + userName);
|
||||
SessionManager.instance.disconnect(user.getSessionId(), DisconnectReason.ConnectingOtherInstance);
|
||||
managerFactory.sessionManager().disconnect(user.getSessionId(), DisconnectReason.ConnectingOtherInstance);
|
||||
}
|
||||
} else {
|
||||
return "User name " + userName + " already in use (or your IP address changed)";
|
||||
|
@ -232,18 +234,18 @@ public class Session {
|
|||
}
|
||||
}
|
||||
User user = selectUser.get();
|
||||
if (!UserManager.instance.connectToSession(sessionId, user.getId())) {
|
||||
if (!managerFactory.userManager().connectToSession(sessionId, user.getId())) {
|
||||
return "Error connecting " + userName;
|
||||
}
|
||||
this.userId = user.getId();
|
||||
if (reconnect) { // must be connected to receive the message
|
||||
Optional<GamesRoom> room = GamesRoomManager.instance.getRoom(GamesRoomManager.instance.getMainRoomId());
|
||||
Optional<GamesRoom> room = managerFactory.gamesRoomManager().getRoom(managerFactory.gamesRoomManager().getMainRoomId());
|
||||
if (!room.isPresent()) {
|
||||
logger.warn("main room not found"); // after server restart users try to use old rooms on reconnect
|
||||
return null;
|
||||
}
|
||||
ChatManager.instance.joinChat(room.get().getChatId(), userId);
|
||||
ChatManager.instance.sendReconnectMessage(userId);
|
||||
managerFactory.chatManager().joinChat(room.get().getChatId(), userId);
|
||||
managerFactory.chatManager().sendReconnectMessage(userId);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -251,12 +253,12 @@ public class Session {
|
|||
|
||||
public void connectAdmin() {
|
||||
this.isAdmin = true;
|
||||
User user = UserManager.instance.createUser("Admin", host, null).orElse(
|
||||
UserManager.instance.getUserByName("Admin").get());
|
||||
User user = managerFactory.userManager().createUser("Admin", host, null).orElse(
|
||||
managerFactory.userManager().getUserByName("Admin").get());
|
||||
UserData adminUserData = UserData.getDefaultUserDataView();
|
||||
adminUserData.setGroupId(UserGroup.ADMIN.getGroupId());
|
||||
user.setUserData(adminUserData);
|
||||
if (!UserManager.instance.connectToSession(sessionId, user.getId())) {
|
||||
if (!managerFactory.userManager().connectToSession(sessionId, user.getId())) {
|
||||
logger.info("Error connecting Admin!");
|
||||
} else {
|
||||
user.setUserState(User.UserState.Connected);
|
||||
|
@ -265,7 +267,7 @@ public class Session {
|
|||
}
|
||||
|
||||
public boolean setUserData(String userName, UserData userData, String clientVersion, String userIdStr) {
|
||||
Optional<User> _user = UserManager.instance.getUserByName(userName);
|
||||
Optional<User> _user = managerFactory.userManager().getUserByName(userName);
|
||||
_user.ifPresent(user -> {
|
||||
if (clientVersion != null) {
|
||||
user.setClientVersion(clientVersion);
|
||||
|
@ -313,7 +315,7 @@ public class Session {
|
|||
|
||||
// because different threads can activate this
|
||||
public void userLostConnection() {
|
||||
Optional<User> _user = UserManager.instance.getUser(userId);
|
||||
Optional<User> _user = managerFactory.userManager().getUser(userId);
|
||||
if (!_user.isPresent()) {
|
||||
return; //user was already disconnected by other thread
|
||||
}
|
||||
|
@ -338,7 +340,7 @@ public class Session {
|
|||
} else {
|
||||
logger.error("SESSION LOCK - kill: userId " + userId);
|
||||
}
|
||||
UserManager.instance.removeUserFromAllTablesAndChat(userId, reason);
|
||||
managerFactory.userManager().removeUserFromAllTablesAndChat(userId, reason);
|
||||
} catch (InterruptedException ex) {
|
||||
logger.error("SESSION LOCK - kill: userId " + userId, ex);
|
||||
} finally {
|
||||
|
@ -372,11 +374,11 @@ public class Session {
|
|||
logger.warn("SESSION LOCK - fireCallback - userId: " + userId + " messageId: " + call.getMessageId(), ex);
|
||||
} catch (HandleCallbackException ex) {
|
||||
this.valid = false;
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
user.setUserState(User.UserState.Disconnected);
|
||||
logger.warn("SESSION CALLBACK EXCEPTION - " + user.getName() + " userId " + userId + " messageId: " + call.getMessageId() + " - cause: " + getBasicCause(ex).toString());
|
||||
logger.trace("Stack trace:", ex);
|
||||
SessionManager.instance.disconnect(sessionId, LostConnection);
|
||||
managerFactory.sessionManager().disconnect(sessionId, LostConnection);
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Unspecific exception:", ex);
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
|
||||
package mage.server;
|
||||
|
||||
import mage.MageException;
|
||||
import mage.players.net.UserData;
|
||||
import mage.server.managers.SessionManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jboss.remoting.callback.InvokerCallbackHandler;
|
||||
|
||||
|
@ -13,21 +14,25 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum SessionManager {
|
||||
public class SessionManagerImpl implements SessionManager {
|
||||
|
||||
instance;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SessionManager.class);
|
||||
private static final Logger logger = Logger.getLogger(SessionManagerImpl.class);
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final ConcurrentHashMap<String, Session> sessions = new ConcurrentHashMap<>();
|
||||
|
||||
public SessionManagerImpl(ManagerFactory managerFactory) {
|
||||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Session> getSession(@Nonnull String sessionId) {
|
||||
Session session = sessions.get(sessionId);
|
||||
if (session == null) {
|
||||
logger.trace("Session with sessionId " + sessionId + " is not found");
|
||||
return Optional.empty();
|
||||
}
|
||||
if (session.getUserId() != null && !UserManager.instance.getUser(session.getUserId()).isPresent()) {
|
||||
if (session.getUserId() != null && !managerFactory.userManager().getUser(session.getUserId()).isPresent()) {
|
||||
logger.error("User for session " + sessionId + " with userId " + session.getUserId() + " is missing. Session removed.");
|
||||
// can happen if user from same host signs in multiple time with multiple clients, after they disconnect with one client
|
||||
disconnect(sessionId, DisconnectReason.ConnectingOtherInstance, session); // direct disconnect
|
||||
|
@ -36,11 +41,13 @@ public enum SessionManager {
|
|||
return Optional.of(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSession(String sessionId, InvokerCallbackHandler callbackHandler) {
|
||||
Session session = new Session(sessionId, callbackHandler);
|
||||
Session session = new Session(managerFactory, sessionId, callbackHandler);
|
||||
sessions.put(sessionId, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerUser(String sessionId, String userName, String password, String email) throws MageException {
|
||||
Session session = sessions.get(sessionId);
|
||||
if (session == null) {
|
||||
|
@ -59,6 +66,7 @@ public enum SessionManager {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connectUser(String sessionId, String userName, String password, String userIdStr) throws MageException {
|
||||
Session session = sessions.get(sessionId);
|
||||
if (session != null) {
|
||||
|
@ -78,6 +86,7 @@ public enum SessionManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connectAdmin(String sessionId) {
|
||||
Session session = sessions.get(sessionId);
|
||||
if (session != null) {
|
||||
|
@ -88,17 +97,20 @@ public enum SessionManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setUserData(String userName, String sessionId, UserData userData, String clientVersion, String userIdStr) throws MageException {
|
||||
return getSession(sessionId)
|
||||
.map(session -> session.setUserData(userName,userData, clientVersion, userIdStr))
|
||||
.orElse(false);
|
||||
return getSession(sessionId)
|
||||
.map(session -> session.setUserData(userName, userData, clientVersion, userIdStr))
|
||||
.orElse(false);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String sessionId, DisconnectReason reason) {
|
||||
disconnect(sessionId, reason, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String sessionId, DisconnectReason reason, Session directSession) {
|
||||
if (directSession == null) {
|
||||
// find real session to disconnects
|
||||
|
@ -115,13 +127,13 @@ public enum SessionManager {
|
|||
break;
|
||||
case ConnectingOtherInstance:
|
||||
case Disconnected: // regular session end or wrong client version
|
||||
UserManager.instance.disconnect(session.getUserId(), reason);
|
||||
managerFactory.userManager().disconnect(session.getUserId(), reason);
|
||||
break;
|
||||
case SessionExpired: // session ends after no reconnect happens in the defined time span
|
||||
break;
|
||||
case LostConnection: // user lost connection - session expires countdown starts
|
||||
session.userLostConnection();
|
||||
UserManager.instance.disconnect(session.getUserId(), reason);
|
||||
managerFactory.userManager().disconnect(session.getUserId(), reason);
|
||||
break;
|
||||
default:
|
||||
logger.trace("endSession: unexpected reason " + reason.toString() + " - sessionId: " + sessionId);
|
||||
|
@ -141,6 +153,7 @@ public enum SessionManager {
|
|||
* @param sessionId
|
||||
* @param userSessionId
|
||||
*/
|
||||
@Override
|
||||
public void disconnectUser(String sessionId, String userSessionId) {
|
||||
if (isAdmin(sessionId)) {
|
||||
getUserFromSession(sessionId).ifPresent(admin -> {
|
||||
|
@ -159,40 +172,46 @@ public enum SessionManager {
|
|||
|
||||
private Optional<User> getUserFromSession(String sessionId) {
|
||||
return getSession(sessionId)
|
||||
.flatMap(s -> UserManager.instance.getUser(s.getUserId()));
|
||||
.flatMap(s -> managerFactory.userManager().getUser(s.getUserId()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endUserSession(String sessionId, String userSessionId) {
|
||||
if (isAdmin(sessionId)) {
|
||||
disconnect(userSessionId, DisconnectReason.AdminDisconnect);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdmin(String sessionId) {
|
||||
return getSession(sessionId).map(Session::isAdmin).orElse(false);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidSession(@Nonnull String sessionId) {
|
||||
return sessions.containsKey(sessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<User> getUser(@Nonnull String sessionId) {
|
||||
Session session = sessions.get(sessionId);
|
||||
if (session != null) {
|
||||
return UserManager.instance.getUser(sessions.get(sessionId).getUserId());
|
||||
return managerFactory.userManager().getUser(sessions.get(sessionId).getUserId());
|
||||
}
|
||||
logger.error(String.format("Session %s could not be found", sessionId));
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean extendUserSession(String sessionId, String pingInfo) {
|
||||
return getSession(sessionId)
|
||||
.map(session -> UserManager.instance.extendUserSession(session.getUserId(), pingInfo))
|
||||
.map(session -> managerFactory.userManager().extendUserSession(session.getUserId(), pingInfo))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendErrorMessageToClient(String sessionId, String message) {
|
||||
Session session = sessions.get(sessionId);
|
||||
if (session == null) {
|
|
@ -20,16 +20,12 @@ import mage.game.tournament.TournamentOptions;
|
|||
import mage.game.tournament.TournamentPlayer;
|
||||
import mage.players.Player;
|
||||
import mage.players.PlayerType;
|
||||
import mage.server.draft.DraftManager;
|
||||
import mage.server.game.GameFactory;
|
||||
import mage.server.game.GameManager;
|
||||
import mage.server.game.PlayerFactory;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.server.record.TableRecorderImpl;
|
||||
import mage.server.tournament.TournamentFactory;
|
||||
import mage.server.tournament.TournamentManager;
|
||||
import mage.server.util.ConfigSettings;
|
||||
import mage.server.util.ServerMessagesUtil;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
import mage.view.ChatMessage;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
@ -47,6 +43,7 @@ public class TableController {
|
|||
|
||||
private static final Logger logger = Logger.getLogger(TableController.class);
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final UUID userId;
|
||||
private final UUID chatId;
|
||||
private final String controllerName;
|
||||
|
@ -58,32 +55,36 @@ public class TableController {
|
|||
private Tournament tournament;
|
||||
|
||||
private ScheduledFuture<?> futureTimeout;
|
||||
protected static final ScheduledExecutorService timeoutExecutor = ThreadExecutor.instance.getTimeoutExecutor();
|
||||
protected final ScheduledExecutorService timeoutExecutor;
|
||||
|
||||
public TableController(UUID roomId, UUID userId, MatchOptions options) {
|
||||
public TableController(ManagerFactory managerFactory, UUID roomId, UUID userId, MatchOptions options) {
|
||||
this.managerFactory = managerFactory;
|
||||
timeoutExecutor = managerFactory.threadExecutor().getTimeoutExecutor();
|
||||
this.userId = userId;
|
||||
this.options = options;
|
||||
match = GameFactory.instance.createMatch(options.getGameType(), options);
|
||||
if (userId != null) {
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
// TODO: Handle if user == null
|
||||
controllerName = user.map(User::getName).orElse("undefined");
|
||||
} else {
|
||||
controllerName = "System";
|
||||
}
|
||||
table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.instance.createDeckValidator(options.getDeckType()),
|
||||
options.getPlayerTypes(), TableRecorderImpl.instance, match, options.getBannedUsers(), options.isPlaneChase());
|
||||
chatId = ChatManager.instance.createChatSession("Match Table " + table.getId());
|
||||
options.getPlayerTypes(), new TableRecorderImpl(managerFactory.userManager()), match, options.getBannedUsers(), options.isPlaneChase());
|
||||
chatId = managerFactory.chatManager().createChatSession("Match Table " + table.getId());
|
||||
init();
|
||||
}
|
||||
|
||||
public TableController(UUID roomId, UUID userId, TournamentOptions options) {
|
||||
public TableController(ManagerFactory managerFactory, UUID roomId, UUID userId, TournamentOptions options) {
|
||||
this.managerFactory = managerFactory;
|
||||
this.timeoutExecutor = managerFactory.threadExecutor().getTimeoutExecutor();
|
||||
this.userId = userId;
|
||||
tournament = TournamentFactory.instance.createTournament(options.getTournamentType(), options);
|
||||
if (userId != null) {
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
if (!user.isPresent()) {
|
||||
logger.fatal(new StringBuilder("User for userId ").append(userId).append(" could not be retrieved from UserManager").toString());
|
||||
logger.fatal(new StringBuilder("User for userId ").append(userId).append(" could not be retrieved from UserManagerImpl").toString());
|
||||
controllerName = "[unknown]";
|
||||
} else {
|
||||
controllerName = user.get().getName();
|
||||
|
@ -92,8 +93,8 @@ public class TableController {
|
|||
controllerName = "System";
|
||||
}
|
||||
table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.instance.createDeckValidator(options.getMatchOptions().getDeckType()),
|
||||
options.getPlayerTypes(), TableRecorderImpl.instance, tournament, options.getMatchOptions().getBannedUsers(), options.isPlaneChase());
|
||||
chatId = ChatManager.instance.createChatSession("Tourn. table " + table.getId());
|
||||
options.getPlayerTypes(), new TableRecorderImpl(managerFactory.userManager()), tournament, options.getMatchOptions().getBannedUsers(), options.isPlaneChase());
|
||||
chatId = managerFactory.chatManager().createChatSession("Tourn. table " + table.getId());
|
||||
}
|
||||
|
||||
private void init() {
|
||||
|
@ -121,7 +122,7 @@ public class TableController {
|
|||
if (seat == null) {
|
||||
throw new GameException("No available seats.");
|
||||
}
|
||||
Optional<User> _user = UserManager.instance.getUser(userId);
|
||||
Optional<User> _user = managerFactory.userManager().getUser(userId);
|
||||
if (!_user.isPresent()) {
|
||||
logger.fatal("couldn't get user " + name + " for join tournament userId = " + userId);
|
||||
return false;
|
||||
|
@ -156,7 +157,7 @@ public class TableController {
|
|||
user.showUserMessage("Join Table", sb.toString());
|
||||
if (isOwner(userId)) {
|
||||
logger.debug("New table removed because owner submitted invalid deck tableId " + table.getId());
|
||||
TableManager.instance.removeTable(table.getId());
|
||||
managerFactory.tableManager().removeTable(table.getId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -231,12 +232,12 @@ public class TableController {
|
|||
newTournamentPlayer.setState(oldTournamentPlayer.getState());
|
||||
newTournamentPlayer.setReplacedTournamentPlayer(oldTournamentPlayer);
|
||||
|
||||
DraftManager.instance.getController(table.getId()).ifPresent(controller -> controller.replacePlayer(oldPlayer, newPlayer));
|
||||
managerFactory.draftManager().getController(table.getId()).ifPresent(controller -> controller.replacePlayer(oldPlayer, newPlayer));
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean joinTable(UUID userId, String name, PlayerType playerType, int skill, DeckCardLists deckList, String password) throws MageException {
|
||||
Optional<User> _user = UserManager.instance.getUser(userId);
|
||||
Optional<User> _user = managerFactory.userManager().getUser(userId);
|
||||
if (!_user.isPresent()) {
|
||||
logger.error("Join Table: can't find user to join " + name + " Id = " + userId);
|
||||
return false;
|
||||
|
@ -274,7 +275,7 @@ public class TableController {
|
|||
user.showUserMessage("Join Table", sb.toString());
|
||||
if (isOwner(userId)) {
|
||||
logger.debug("New table removed because owner submitted invalid deck tableId " + table.getId());
|
||||
TableManager.instance.removeTable(table.getId());
|
||||
managerFactory.tableManager().removeTable(table.getId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -420,7 +421,7 @@ public class TableController {
|
|||
}
|
||||
}
|
||||
if (!Main.isTestMode() && !table.getValidator().validate(deck)) {
|
||||
Optional<User> _user = UserManager.instance.getUser(userId);
|
||||
Optional<User> _user = managerFactory.userManager().getUser(userId);
|
||||
if (!_user.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -453,10 +454,10 @@ public class TableController {
|
|||
private void submitDeck(UUID userId, UUID playerId, Deck deck) {
|
||||
if (table.getState() == TableState.SIDEBOARDING) {
|
||||
match.submitDeck(playerId, deck);
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.removeSideboarding(table.getId()));
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> user.removeSideboarding(table.getId()));
|
||||
} else {
|
||||
TournamentManager.instance.submitDeck(tournament.getId(), playerId, deck);
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.removeConstructing(playerId));
|
||||
managerFactory.tournamentManager().submitDeck(tournament.getId(), playerId, deck);
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> user.removeConstructing(playerId));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -464,7 +465,7 @@ public class TableController {
|
|||
boolean validDeck = true;
|
||||
if (table.isTournament()) {
|
||||
if (tournament != null) {
|
||||
validDeck = TournamentManager.instance.updateDeck(tournament.getId(), playerId, deck);
|
||||
validDeck = managerFactory.tournamentManager().updateDeck(tournament.getId(), playerId, deck);
|
||||
} else {
|
||||
logger.fatal("Tournament == null table: " + table.getId() + " userId: " + userId);
|
||||
}
|
||||
|
@ -478,7 +479,7 @@ public class TableController {
|
|||
|
||||
public boolean watchTable(UUID userId) {
|
||||
if (table.isTournament()) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.ccShowTournament(table.getTournament().getId()));
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> user.ccShowTournament(table.getTournament().getId()));
|
||||
return true;
|
||||
} else {
|
||||
if (table.isTournamentSubTable() && !table.getTournament().getOptions().isWatchingAllowed()) {
|
||||
|
@ -491,7 +492,7 @@ public class TableController {
|
|||
if (userPlayerMap.get(userId) != null) {
|
||||
return false;
|
||||
}
|
||||
Optional<User> _user = UserManager.instance.getUser(userId);
|
||||
Optional<User> _user = managerFactory.userManager().getUser(userId);
|
||||
if (!_user.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -533,7 +534,7 @@ public class TableController {
|
|||
&& (table.getState() == TableState.WAITING
|
||||
|| table.getState() == TableState.READY_TO_START)) {
|
||||
// table not started yet and user is the owner, removeUserFromAllTablesAndChat the table
|
||||
TableManager.instance.removeTable(table.getId());
|
||||
managerFactory.tableManager().removeTable(table.getId());
|
||||
} else {
|
||||
UUID playerId = userPlayerMap.get(userId);
|
||||
if (playerId != null) {
|
||||
|
@ -544,9 +545,9 @@ public class TableController {
|
|||
} else {
|
||||
match.quitMatch(playerId);
|
||||
}
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
if (user.isPresent()) {
|
||||
ChatManager.instance.broadcast(chatId, user.get().getName(), "has left the table", ChatMessage.MessageColor.BLUE, true, null, ChatMessage.MessageType.STATUS, ChatMessage.SoundToPlay.PlayerLeft);
|
||||
managerFactory.chatManager().broadcast(chatId, user.get().getName(), "has left the table", ChatMessage.MessageColor.BLUE, true, null, ChatMessage.MessageType.STATUS, ChatMessage.SoundToPlay.PlayerLeft);
|
||||
if (!table.isTournamentSubTable()) {
|
||||
user.get().removeTable(playerId);
|
||||
}
|
||||
|
@ -557,9 +558,9 @@ public class TableController {
|
|||
} else if (table.getState() != TableState.FINISHED) {
|
||||
if (table.isTournament()) {
|
||||
logger.debug("Quit tournament sub tables for userId: " + userId);
|
||||
TableManager.instance.userQuitTournamentSubTables(tournament.getId(), userId);
|
||||
managerFactory.tableManager().userQuitTournamentSubTables(tournament.getId(), userId);
|
||||
logger.debug("Quit tournament Id: " + table.getTournament().getId() + '(' + table.getTournament().getTournamentState() + ')');
|
||||
TournamentManager.instance.quit(tournament.getId(), userId);
|
||||
managerFactory.tournamentManager().quit(tournament.getId(), userId);
|
||||
} else {
|
||||
MatchPlayer matchPlayer = match.getPlayer(playerId);
|
||||
if (matchPlayer != null && !match.hasEnded() && !matchPlayer.hasQuit()) {
|
||||
|
@ -567,7 +568,7 @@ public class TableController {
|
|||
if (game != null && !game.hasEnded()) {
|
||||
Player player = match.getPlayer(playerId).getPlayer();
|
||||
if (player != null && player.isInGame()) {
|
||||
GameManager.instance.quitMatch(game.getId(), userId);
|
||||
managerFactory.gameManager().quitMatch(game.getId(), userId);
|
||||
}
|
||||
match.quitMatch(playerId);
|
||||
} else {
|
||||
|
@ -605,7 +606,7 @@ public class TableController {
|
|||
if (table.isTournamentSubTable()) {
|
||||
logger.info("Tourn. match started id:" + match.getId() + " tournId: " + table.getTournament().getId());
|
||||
} else {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
logger.info("MATCH started [" + match.getName() + "] " + match.getId() + '(' + user.getName() + ')');
|
||||
logger.debug("- " + match.getOptions().getGameType() + " - " + match.getOptions().getDeckType());
|
||||
});
|
||||
|
@ -628,12 +629,12 @@ public class TableController {
|
|||
gameOptions.bannedUsers = match.getOptions().getBannedUsers();
|
||||
gameOptions.planeChase = match.getOptions().isPlaneChase();
|
||||
match.getGame().setGameOptions(gameOptions);
|
||||
GameManager.instance.createGameSession(match.getGame(), userPlayerMap, table.getId(), choosingPlayerId, gameOptions);
|
||||
managerFactory.gameManager().createGameSession(match.getGame(), userPlayerMap, table.getId(), choosingPlayerId, gameOptions);
|
||||
String creator = null;
|
||||
StringBuilder opponent = new StringBuilder();
|
||||
for (Entry<UUID, UUID> entry : userPlayerMap.entrySet()) { // do only for no AI players
|
||||
if (match.getPlayer(entry.getValue()) != null && !match.getPlayer(entry.getValue()).hasQuit()) {
|
||||
Optional<User> _user = UserManager.instance.getUser(entry.getKey());
|
||||
Optional<User> _user = managerFactory.userManager().getUser(entry.getKey());
|
||||
if (_user.isPresent()) {
|
||||
User user = _user.get();
|
||||
user.ccGameStarted(match.getGame().getId(), entry.getValue());
|
||||
|
@ -670,17 +671,17 @@ public class TableController {
|
|||
logger.info("GAME started " + (match.getGame() != null ? match.getGame().getId() : "no Game") + " [" + match.getName() + "] " + creator + " - " + opponent.toString());
|
||||
logger.debug("- matchId: " + match.getId() + " [" + match.getName() + ']');
|
||||
if (match.getGame() != null) {
|
||||
logger.debug("- chatId: " + GameManager.instance.getChatId(match.getGame().getId()));
|
||||
logger.debug("- chatId: " + managerFactory.gameManager().getChatId(match.getGame().getId()));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.fatal("Error starting game table: " + table.getId(), ex);
|
||||
if (table != null) {
|
||||
TableManager.instance.removeTable(table.getId());
|
||||
managerFactory.tableManager().removeTable(table.getId());
|
||||
}
|
||||
if (match != null) {
|
||||
Game game = match.getGame();
|
||||
if (game != null) {
|
||||
GameManager.instance.removeGame(game.getId());
|
||||
managerFactory.gameManager().removeGame(game.getId());
|
||||
// game ended by error, so don't add it to ended stats
|
||||
}
|
||||
}
|
||||
|
@ -691,9 +692,9 @@ public class TableController {
|
|||
try {
|
||||
if (userId.equals(this.userId) && table.getState() == TableState.STARTING) {
|
||||
tournament.setStartTime();
|
||||
TournamentManager.instance.createTournamentSession(tournament, userPlayerMap, table.getId());
|
||||
managerFactory.tournamentManager().createTournamentSession(tournament, userPlayerMap, table.getId());
|
||||
for (Entry<UUID, UUID> entry : userPlayerMap.entrySet()) {
|
||||
UserManager.instance.getUser(entry.getKey()).ifPresent(user -> {
|
||||
managerFactory.userManager().getUser(entry.getKey()).ifPresent(user -> {
|
||||
logger.info(new StringBuilder("User ").append(user.getName()).append(" tournament started: ").append(tournament.getId()).append(" userId: ").append(user.getId()));
|
||||
user.ccTournamentStarted(tournament.getId(), entry.getValue());
|
||||
});
|
||||
|
@ -702,16 +703,16 @@ public class TableController {
|
|||
}
|
||||
} catch (Exception ex) {
|
||||
logger.fatal("Error starting tournament", ex);
|
||||
TableManager.instance.removeTable(table.getId());
|
||||
TournamentManager.instance.quit(tournament.getId(), userId);
|
||||
managerFactory.tableManager().removeTable(table.getId());
|
||||
managerFactory.tournamentManager().quit(tournament.getId(), userId);
|
||||
}
|
||||
}
|
||||
|
||||
public void startDraft(Draft draft) {
|
||||
table.initDraft();
|
||||
DraftManager.instance.createDraftSession(draft, userPlayerMap, table.getId());
|
||||
managerFactory.draftManager().createDraftSession(draft, userPlayerMap, table.getId());
|
||||
for (Entry<UUID, UUID> entry : userPlayerMap.entrySet()) {
|
||||
Optional<User> user = UserManager.instance.getUser(entry.getKey());
|
||||
Optional<User> user = managerFactory.userManager().getUser(entry.getKey());
|
||||
if (user.isPresent()) {
|
||||
logger.info(new StringBuilder("User ").append(user.get().getName()).append(" draft started: ").append(draft.getId()).append(" userId: ").append(user.get().getId()));
|
||||
user.get().ccDraftStarted(draft.getId(), entry.getValue());
|
||||
|
@ -725,7 +726,7 @@ public class TableController {
|
|||
|
||||
for (Entry<UUID, UUID> entry : userPlayerMap.entrySet()) {
|
||||
if (entry.getValue().equals(playerId)) {
|
||||
Optional<User> user = UserManager.instance.getUser(entry.getKey());
|
||||
Optional<User> user = managerFactory.userManager().getUser(entry.getKey());
|
||||
int remaining = (int) futureTimeout.getDelay(TimeUnit.SECONDS);
|
||||
user.ifPresent(user1 -> user1.ccSideboard(deck, table.getId(), remaining, options.isLimited()));
|
||||
break;
|
||||
|
@ -767,12 +768,12 @@ public class TableController {
|
|||
}
|
||||
UUID choosingPlayerId = match.getChooser();
|
||||
match.endGame();
|
||||
if (ConfigSettings.instance.isSaveGameActivated() && !game.isSimulation()) {
|
||||
if (GameManager.instance.saveGame(game.getId())) {
|
||||
if (managerFactory.configSettings().isSaveGameActivated() && !game.isSimulation()) {
|
||||
if (managerFactory.gameManager().saveGame(game.getId())) {
|
||||
match.setReplayAvailable(true);
|
||||
}
|
||||
}
|
||||
GameManager.instance.removeGame(game.getId());
|
||||
managerFactory.gameManager().removeGame(game.getId());
|
||||
ServerMessagesUtil.instance.incGamesEnded();
|
||||
|
||||
try {
|
||||
|
@ -835,7 +836,7 @@ public class TableController {
|
|||
// opponent(s) left during sideboarding
|
||||
if (matchPlayer != null) {
|
||||
if (!matchPlayer.hasQuit()) {
|
||||
UserManager.instance.getUser(entry.getKey()).ifPresent(user -> {
|
||||
managerFactory.userManager().getUser(entry.getKey()).ifPresent(user -> {
|
||||
if (table.getState() == TableState.SIDEBOARDING) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (table.isTournamentSubTable()) {
|
||||
|
@ -860,7 +861,7 @@ public class TableController {
|
|||
}
|
||||
}
|
||||
// free resources no longer needed
|
||||
match.cleanUpOnMatchEnd(ConfigSettings.instance.isSaveGameActivated(), table.isTournament());
|
||||
match.cleanUpOnMatchEnd(managerFactory.configSettings().isSaveGameActivated(), table.isTournament());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -932,13 +933,13 @@ public class TableController {
|
|||
public boolean isTournamentStillValid() {
|
||||
if (table.getTournament() != null) {
|
||||
if (table.getState() != TableState.WAITING && table.getState() != TableState.READY_TO_START && table.getState() != TableState.STARTING) {
|
||||
return TournamentManager.instance.getTournamentController(table.getTournament().getId())
|
||||
return managerFactory.tournamentManager().getTournamentController(table.getTournament().getId())
|
||||
.map(tc -> tc.isTournamentStillValid(table.getState()))
|
||||
.orElse(false);
|
||||
|
||||
} else {
|
||||
// check if table creator is still a valid user, if not removeUserFromAllTablesAndChat table
|
||||
return UserManager.instance.getUser(userId).isPresent();
|
||||
return managerFactory.userManager().getUser(userId).isPresent();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -1004,7 +1005,7 @@ public class TableController {
|
|||
|| table.getState() == TableState.READY_TO_START)
|
||||
|| !match.isDoneSideboarding()
|
||||
|| (!matchPlayer.hasQuit() && match.getGame() != null && matchPlayer.getPlayer().isInGame())) {
|
||||
Optional<User> user = UserManager.instance.getUser(userPlayerEntry.getKey());
|
||||
Optional<User> user = managerFactory.userManager().getUser(userPlayerEntry.getKey());
|
||||
if (!user.isPresent() || !user.get().isActive()) {
|
||||
logger.warn("- Active user of match is missing: " + matchPlayer.getName());
|
||||
logger.warn("-- matchId:" + match.getId());
|
||||
|
@ -1028,12 +1029,12 @@ public class TableController {
|
|||
void cleanUp() {
|
||||
if (!table.isTournamentSubTable()) {
|
||||
for (Map.Entry<UUID, UUID> entry : userPlayerMap.entrySet()) {
|
||||
UserManager.instance.getUser(entry.getKey()).ifPresent(user
|
||||
managerFactory.userManager().getUser(entry.getKey()).ifPresent(user
|
||||
-> user.removeTable(entry.getValue()));
|
||||
}
|
||||
|
||||
}
|
||||
ChatManager.instance.destroyChatSession(chatId);
|
||||
managerFactory.chatManager().destroyChatSession(chatId);
|
||||
}
|
||||
|
||||
public synchronized TableState getTableState() {
|
||||
|
|
|
@ -14,9 +14,8 @@ import mage.game.tournament.TournamentOptions;
|
|||
import mage.game.tournament.TournamentPlayer;
|
||||
import mage.players.PlayerType;
|
||||
import mage.server.game.GameController;
|
||||
import mage.server.game.GameManager;
|
||||
import mage.server.game.GamesRoomManager;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
import mage.server.managers.TableManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.text.DateFormat;
|
||||
|
@ -34,12 +33,12 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum TableManager {
|
||||
instance;
|
||||
public class TableManagerImpl implements TableManager {
|
||||
protected final ScheduledExecutorService expireExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
// protected static ScheduledExecutorService expireExecutor = ThreadExecutor.getInstance().getExpireExecutor();
|
||||
private final Logger logger = Logger.getLogger(TableManager.class);
|
||||
// protected static ScheduledExecutorService expireExecutor = ThreadExecutorImpl.getInstance().getExpireExecutor();
|
||||
private final ManagerFactory managerFactory;
|
||||
private final Logger logger = Logger.getLogger(TableManagerImpl.class);
|
||||
private final DateFormat formatter = new SimpleDateFormat("HH:mm:ss");
|
||||
|
||||
private final ConcurrentHashMap<UUID, TableController> controllers = new ConcurrentHashMap<>();
|
||||
|
@ -55,10 +54,14 @@ public enum TableManager {
|
|||
*/
|
||||
private static final int EXPIRE_CHECK_PERIOD = 10;
|
||||
|
||||
TableManager() {
|
||||
public TableManagerImpl(ManagerFactory managerFactory) {
|
||||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
expireExecutor.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
ChatManager.instance.clearUserMessageStorage();
|
||||
managerFactory.chatManager().clearUserMessageStorage();
|
||||
checkTableHealthState();
|
||||
} catch (Exception ex) {
|
||||
logger.fatal("Check table health state job error:", ex);
|
||||
|
@ -66,22 +69,25 @@ public enum TableManager {
|
|||
}, EXPIRE_CHECK_PERIOD, EXPIRE_CHECK_PERIOD, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table createTable(UUID roomId, UUID userId, MatchOptions options) {
|
||||
TableController tableController = new TableController(roomId, userId, options);
|
||||
TableController tableController = new TableController(managerFactory, roomId, userId, options);
|
||||
putControllers(tableController.getTable().getId(), tableController);
|
||||
putTables(tableController.getTable().getId(), tableController.getTable());
|
||||
return tableController.getTable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table createTable(UUID roomId, MatchOptions options) {
|
||||
TableController tableController = new TableController(roomId, null, options);
|
||||
TableController tableController = new TableController(managerFactory, roomId, null, options);
|
||||
putControllers(tableController.getTable().getId(), tableController);
|
||||
putTables(tableController.getTable().getId(), tableController.getTable());
|
||||
return tableController.getTable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table createTournamentTable(UUID roomId, UUID userId, TournamentOptions options) {
|
||||
TableController tableController = new TableController(roomId, userId, options);
|
||||
TableController tableController = new TableController(managerFactory, roomId, userId, options);
|
||||
putControllers(tableController.getTable().getId(), tableController);
|
||||
putTables(tableController.getTable().getId(), tableController.getTable());
|
||||
return tableController.getTable();
|
||||
|
@ -107,10 +113,12 @@ public enum TableManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table getTable(UUID tableId) {
|
||||
return tables.get(tableId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Match> getMatch(UUID tableId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
return Optional.of(controllers.get(tableId).getMatch());
|
||||
|
@ -118,6 +126,7 @@ public enum TableManager {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Table> getTables() {
|
||||
Collection<Table> newTables = new ArrayList<>();
|
||||
final Lock r = tablesLock.readLock();
|
||||
|
@ -130,6 +139,7 @@ public enum TableManager {
|
|||
return newTables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<TableController> getControllers() {
|
||||
Collection<TableController> newControllers = new ArrayList<>();
|
||||
final Lock r = controllersLock.readLock();
|
||||
|
@ -142,6 +152,7 @@ public enum TableManager {
|
|||
return newControllers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TableController> getController(UUID tableId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
return Optional.of(controllers.get(tableId));
|
||||
|
@ -149,6 +160,7 @@ public enum TableManager {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean joinTable(UUID userId, UUID tableId, String name, PlayerType playerType, int skill, DeckCardLists deckList, String password) throws MageException {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
return controllers.get(tableId).joinTable(userId, name, playerType, skill, deckList, password);
|
||||
|
@ -156,6 +168,7 @@ public enum TableManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean joinTournament(UUID userId, UUID tableId, String name, PlayerType playerType, int skill, DeckCardLists deckList, String password) throws GameException {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
return controllers.get(tableId).joinTournament(userId, name, playerType, skill, deckList, password);
|
||||
|
@ -163,11 +176,12 @@ public enum TableManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean submitDeck(UUID userId, UUID tableId, DeckCardLists deckList) throws MageException {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
return controllers.get(tableId).submitDeck(userId, deckList);
|
||||
}
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
user.removeSideboarding(tableId);
|
||||
user.showUserMessage("Submit deck", "Table no longer active");
|
||||
|
||||
|
@ -176,6 +190,7 @@ public enum TableManager {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDeck(UUID userId, UUID tableId, DeckCardLists deckList) throws MageException {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
controllers.get(tableId).updateDeck(userId, deckList);
|
||||
|
@ -183,6 +198,7 @@ public enum TableManager {
|
|||
}
|
||||
|
||||
// removeUserFromAllTablesAndChat user from all tournament sub tables
|
||||
@Override
|
||||
public void userQuitTournamentSubTables(UUID userId) {
|
||||
for (TableController controller : getControllers()) {
|
||||
if (controller.getTable() != null) {
|
||||
|
@ -190,12 +206,13 @@ public enum TableManager {
|
|||
controller.leaveTable(userId);
|
||||
}
|
||||
} else {
|
||||
logger.error("TableManager.userQuitTournamentSubTables table == null - userId " + userId);
|
||||
logger.error("TableManagerImpl.userQuitTournamentSubTables table == null - userId " + userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// removeUserFromAllTablesAndChat user from all sub tables of a tournament
|
||||
@Override
|
||||
public void userQuitTournamentSubTables(UUID tournamentId, UUID userId) {
|
||||
for (TableController controller : getControllers()) {
|
||||
if (controller.getTable().isTournamentSubTable() && controller.getTable().getTournament().getId().equals(tournamentId)) {
|
||||
|
@ -206,6 +223,7 @@ public enum TableManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTableOwner(UUID tableId, UUID userId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
return controllers.get(tableId).isOwner(userId);
|
||||
|
@ -213,13 +231,14 @@ public enum TableManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeTable(UUID userId, UUID tableId) {
|
||||
if (isTableOwner(tableId, userId) || UserManager.instance.isAdmin(userId)) {
|
||||
if (isTableOwner(tableId, userId) || managerFactory.userManager().isAdmin(userId)) {
|
||||
logger.debug("Table remove request - userId: " + userId + " tableId: " + tableId);
|
||||
TableController tableController = controllers.get(tableId);
|
||||
if (tableController != null) {
|
||||
tableController.leaveTableAll();
|
||||
ChatManager.instance.destroyChatSession(tableController.getChatId());
|
||||
managerFactory.chatManager().destroyChatSession(tableController.getChatId());
|
||||
removeTable(tableId);
|
||||
}
|
||||
return true;
|
||||
|
@ -227,6 +246,7 @@ public enum TableManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveTable(UUID userId, UUID tableId) {
|
||||
TableController tableController = controllers.get(tableId);
|
||||
if (tableController != null) {
|
||||
|
@ -234,6 +254,7 @@ public enum TableManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<UUID> getChatId(UUID tableId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
return Optional.of(controllers.get(tableId).getChatId());
|
||||
|
@ -248,11 +269,12 @@ public enum TableManager {
|
|||
* @param roomId
|
||||
* @param tableId
|
||||
*/
|
||||
@Override
|
||||
public void startMatch(UUID userId, UUID roomId, UUID tableId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
controllers.get(tableId).startMatch(userId);
|
||||
// chat of start dialog can be killed
|
||||
ChatManager.instance.destroyChatSession(controllers.get(tableId).getChatId());
|
||||
managerFactory.chatManager().destroyChatSession(controllers.get(tableId).getChatId());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,25 +284,29 @@ public enum TableManager {
|
|||
* @param roomId
|
||||
* @param tableId
|
||||
*/
|
||||
@Override
|
||||
public void startTournamentSubMatch(UUID roomId, UUID tableId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
controllers.get(tableId).startMatch();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startTournament(UUID userId, UUID roomId, UUID tableId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
controllers.get(tableId).startTournament(userId);
|
||||
ChatManager.instance.destroyChatSession(controllers.get(tableId).getChatId());
|
||||
managerFactory.chatManager().destroyChatSession(controllers.get(tableId).getChatId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startDraft(UUID tableId, Draft draft) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
controllers.get(tableId).startDraft(draft);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean watchTable(UUID userId, UUID tableId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
return controllers.get(tableId).watchTable(userId);
|
||||
|
@ -288,6 +314,7 @@ public enum TableManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endGame(UUID tableId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
if (controllers.get(tableId).endGameAndStartNextGame()) {
|
||||
|
@ -296,42 +323,49 @@ public enum TableManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endDraft(UUID tableId, Draft draft) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
controllers.get(tableId).endDraft(draft);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endTournament(UUID tableId, Tournament tournament) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
controllers.get(tableId).endTournament(tournament);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swapSeats(UUID tableId, UUID userId, int seatNum1, int seatNum2) {
|
||||
if (controllers.containsKey(tableId) && isTableOwner(tableId, userId)) {
|
||||
controllers.get(tableId).swapSeats(seatNum1, seatNum2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void construct(UUID tableId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
controllers.get(tableId).construct();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initTournament(UUID tableId) {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
controllers.get(tableId).initTournament();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPlayer(UUID userId, UUID tableId, TournamentPlayer player) throws GameException {
|
||||
if (controllers.containsKey(tableId)) {
|
||||
controllers.get(tableId).addPlayer(userId, player.getPlayer(), player.getPlayerType(), player.getDeck());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTable(UUID tableId) {
|
||||
TableController tableController = controllers.get(tableId);
|
||||
if (tableController != null) {
|
||||
|
@ -365,21 +399,22 @@ public enum TableManager {
|
|||
// If table is not finished, the table has to be removed completly because it's not a normal state (if finished it will be removed in GamesRoomImpl.Update())
|
||||
if (table.getState() != TableState.FINISHED) {
|
||||
if (game != null) {
|
||||
GameManager.instance.removeGame(game.getId());
|
||||
managerFactory.gameManager().removeGame(game.getId());
|
||||
// something goes wrong, so don't add it to ended stats
|
||||
}
|
||||
GamesRoomManager.instance.removeTable(tableId);
|
||||
managerFactory.gamesRoomManager().removeTable(tableId);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugServerState() {
|
||||
logger.debug("--- Server state ----------------------------------------------");
|
||||
Collection<User> users = UserManager.instance.getUsers();
|
||||
Collection<User> users = managerFactory.userManager().getUsers();
|
||||
logger.debug("--------User: " + users.size() + " [userId | since | lock | name -----------------------");
|
||||
for (User user : users) {
|
||||
Optional<Session> session = SessionManager.instance.getSession(user.getSessionId());
|
||||
Optional<Session> session = managerFactory.sessionManager().getSession(user.getSessionId());
|
||||
String sessionState = "N";
|
||||
if (session.isPresent()) {
|
||||
if (session.get().isLocked()) {
|
||||
|
@ -393,14 +428,14 @@ public enum TableManager {
|
|||
+ " | " + sessionState
|
||||
+ " | " + user.getName() + " (" + user.getUserState().toString() + " - " + user.getPingInfo() + ')');
|
||||
}
|
||||
List<ChatSession> chatSessions = ChatManager.instance.getChatSessions();
|
||||
List<ChatSession> chatSessions = managerFactory.chatManager().getChatSessions();
|
||||
logger.debug("------- ChatSessions: " + chatSessions.size() + " ----------------------------------");
|
||||
for (ChatSession chatSession : chatSessions) {
|
||||
logger.debug(chatSession.getChatId() + " " + formatter.format(chatSession.getCreateTime()) + ' ' + chatSession.getInfo() + ' ' + chatSession.getClients().values().toString());
|
||||
}
|
||||
logger.debug("------- Games: " + GameManager.instance.getNumberActiveGames() + " --------------------------------------------");
|
||||
logger.debug(" Active Game Worker: " + ThreadExecutor.instance.getActiveThreads(ThreadExecutor.instance.getGameExecutor()));
|
||||
for (Entry<UUID, GameController> entry : GameManager.instance.getGameController().entrySet()) {
|
||||
logger.debug("------- Games: " + managerFactory.gameManager().getNumberActiveGames() + " --------------------------------------------");
|
||||
logger.debug(" Active Game Worker: " + managerFactory.threadExecutor().getActiveThreads(managerFactory.threadExecutor().getGameExecutor()));
|
||||
for (Entry<UUID, GameController> entry : managerFactory.gameManager().getGameController().entrySet()) {
|
||||
logger.debug(entry.getKey() + entry.getValue().getPlayerNameList());
|
||||
}
|
||||
logger.debug("--- Server state END ------------------------------------------");
|
|
@ -10,14 +10,13 @@ import mage.interfaces.callback.ClientCallback;
|
|||
import mage.interfaces.callback.ClientCallbackMethod;
|
||||
import mage.players.net.UserData;
|
||||
import mage.server.draft.DraftSession;
|
||||
import mage.server.game.GameManager;
|
||||
import mage.server.game.GameSessionPlayer;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.server.rating.GlickoRating;
|
||||
import mage.server.rating.GlickoRatingSystem;
|
||||
import mage.server.record.UserStats;
|
||||
import mage.server.record.UserStatsRepository;
|
||||
import mage.server.tournament.TournamentController;
|
||||
import mage.server.tournament.TournamentManager;
|
||||
import mage.server.tournament.TournamentSession;
|
||||
import mage.server.util.ServerMessagesUtil;
|
||||
import mage.server.util.SystemUtil;
|
||||
|
@ -43,6 +42,7 @@ public class User {
|
|||
Offline // set if the user was disconnected and expired or regularly left XMage. Removed is the user later after some time
|
||||
}
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final UUID userId;
|
||||
private final String userName;
|
||||
private final String host;
|
||||
|
@ -68,7 +68,8 @@ public class User {
|
|||
private String clientVersion;
|
||||
private String userIdStr;
|
||||
|
||||
public User(String userName, String host, AuthorizedUser authorizedUser) {
|
||||
public User(ManagerFactory managerFactory, String userName, String host, AuthorizedUser authorizedUser) {
|
||||
this.managerFactory = managerFactory;
|
||||
this.userId = UUID.randomUUID();
|
||||
this.userName = userName;
|
||||
this.host = host;
|
||||
|
@ -181,7 +182,7 @@ public class User {
|
|||
// Because watched games don't get restored after reconnection call stop watching
|
||||
for (Iterator<UUID> iterator = watchedGames.iterator(); iterator.hasNext(); ) {
|
||||
UUID gameId = iterator.next();
|
||||
GameManager.instance.stopWatching(gameId, userId);
|
||||
managerFactory.gameManager().stopWatching(gameId, userId);
|
||||
iterator.remove();
|
||||
}
|
||||
ServerMessagesUtil.instance.incLostConnection();
|
||||
|
@ -227,7 +228,7 @@ public class User {
|
|||
|
||||
public void fireCallback(final ClientCallback call) {
|
||||
if (isConnected()) {
|
||||
SessionManager.instance.getSession(sessionId).ifPresent(session
|
||||
managerFactory.sessionManager().getSession(sessionId).ifPresent(session
|
||||
-> session.fireCallback(call)
|
||||
);
|
||||
}
|
||||
|
@ -288,27 +289,27 @@ public class User {
|
|||
|
||||
public void sendPlayerUUID(final UUID gameId, final UUID data) {
|
||||
lastActivity = new Date();
|
||||
GameManager.instance.sendPlayerUUID(gameId, userId, data);
|
||||
managerFactory.gameManager().sendPlayerUUID(gameId, userId, data);
|
||||
}
|
||||
|
||||
public void sendPlayerString(final UUID gameId, final String data) {
|
||||
lastActivity = new Date();
|
||||
GameManager.instance.sendPlayerString(gameId, userId, data);
|
||||
managerFactory.gameManager().sendPlayerString(gameId, userId, data);
|
||||
}
|
||||
|
||||
public void sendPlayerManaType(final UUID gameId, final UUID playerId, final ManaType data) {
|
||||
lastActivity = new Date();
|
||||
GameManager.instance.sendPlayerManaType(gameId, playerId, userId, data);
|
||||
managerFactory.gameManager().sendPlayerManaType(gameId, playerId, userId, data);
|
||||
}
|
||||
|
||||
public void sendPlayerBoolean(final UUID gameId, final Boolean data) {
|
||||
lastActivity = new Date();
|
||||
GameManager.instance.sendPlayerBoolean(gameId, userId, data);
|
||||
managerFactory.gameManager().sendPlayerBoolean(gameId, userId, data);
|
||||
}
|
||||
|
||||
public void sendPlayerInteger(final UUID gameId, final Integer data) {
|
||||
lastActivity = new Date();
|
||||
GameManager.instance.sendPlayerInteger(gameId, userId, data);
|
||||
managerFactory.gameManager().sendPlayerInteger(gameId, userId, data);
|
||||
}
|
||||
|
||||
public void updateLastActivity(String pingInfo) {
|
||||
|
@ -338,7 +339,7 @@ public class User {
|
|||
}
|
||||
for (Iterator<Entry<UUID, UUID>> iterator = userTournaments.entrySet().iterator(); iterator.hasNext(); ) {
|
||||
Entry<UUID, UUID> next = iterator.next();
|
||||
Optional<TournamentController> tournamentController = TournamentManager.instance.getTournamentController(next.getValue());
|
||||
Optional<TournamentController> tournamentController = managerFactory.tournamentManager().getTournamentController(next.getValue());
|
||||
if (tournamentController.isPresent()) {
|
||||
ccTournamentStarted(next.getValue(), next.getKey());
|
||||
tournamentController.get().rejoin(next.getKey());
|
||||
|
@ -349,7 +350,7 @@ public class User {
|
|||
for (Entry<UUID, GameSessionPlayer> entry : gameSessions.entrySet()) {
|
||||
ccGameStarted(entry.getValue().getGameId(), entry.getKey());
|
||||
entry.getValue().init();
|
||||
GameManager.instance.sendPlayerString(entry.getValue().getGameId(), userId, "");
|
||||
managerFactory.gameManager().sendPlayerString(entry.getValue().getGameId(), userId, "");
|
||||
}
|
||||
|
||||
for (Entry<UUID, DraftSession> entry : draftSessions.entrySet()) {
|
||||
|
@ -362,7 +363,7 @@ public class User {
|
|||
entry.getValue().construct(0); // TODO: Check if this is correct
|
||||
}
|
||||
for (Entry<UUID, Deck> entry : sideboarding.entrySet()) {
|
||||
Optional<TableController> controller = TableManager.instance.getController(entry.getKey());
|
||||
Optional<TableController> controller = managerFactory.tableManager().getController(entry.getKey());
|
||||
if (controller.isPresent()) {
|
||||
ccSideboard(entry.getValue(), entry.getKey(), controller.get().getRemainingTime(), controller.get().getOptions().isLimited());
|
||||
} else {
|
||||
|
@ -427,32 +428,32 @@ public class User {
|
|||
draftSessions.clear();
|
||||
logger.trace("REMOVE " + userName + " Tournament sessions " + userTournaments.size());
|
||||
for (UUID tournamentId : userTournaments.values()) {
|
||||
TournamentManager.instance.quit(tournamentId, userId);
|
||||
managerFactory.tournamentManager().quit(tournamentId, userId);
|
||||
}
|
||||
userTournaments.clear();
|
||||
constructing.clear();
|
||||
logger.trace("REMOVE " + userName + " Tables " + tables.size());
|
||||
for (Entry<UUID, Table> entry : tables.entrySet()) {
|
||||
logger.debug("-- leave tableId: " + entry.getValue().getId());
|
||||
TableManager.instance.leaveTable(userId, entry.getValue().getId());
|
||||
managerFactory.tableManager().leaveTable(userId, entry.getValue().getId());
|
||||
}
|
||||
tables.clear();
|
||||
sideboarding.clear();
|
||||
logger.trace("REMOVE " + userName + " Game sessions: " + gameSessions.size());
|
||||
for (GameSessionPlayer gameSessionPlayer : gameSessions.values()) {
|
||||
logger.debug("-- kill game session of gameId: " + gameSessionPlayer.getGameId());
|
||||
GameManager.instance.quitMatch(gameSessionPlayer.getGameId(), userId);
|
||||
managerFactory.gameManager().quitMatch(gameSessionPlayer.getGameId(), userId);
|
||||
gameSessionPlayer.quitGame();
|
||||
}
|
||||
gameSessions.clear();
|
||||
logger.trace("REMOVE " + userName + " watched Games " + watchedGames.size());
|
||||
for (Iterator<UUID> it = watchedGames.iterator(); it.hasNext(); ) { // Iterator to prevent ConcurrentModificationException
|
||||
UUID gameId = it.next();
|
||||
GameManager.instance.stopWatching(gameId, userId);
|
||||
managerFactory.gameManager().stopWatching(gameId, userId);
|
||||
}
|
||||
watchedGames.clear();
|
||||
logger.trace("REMOVE " + userName + " Chats ");
|
||||
ChatManager.instance.removeUser(userId, reason);
|
||||
managerFactory.chatManager().removeUser(userId, reason);
|
||||
}
|
||||
|
||||
public void setUserData(UserData userData) {
|
||||
|
@ -788,7 +789,7 @@ public class User {
|
|||
if (table.getState() == TableState.FINISHED) {
|
||||
number++;
|
||||
} else {
|
||||
Optional<TableController> tableController = TableManager.instance.getController(table.getId());
|
||||
Optional<TableController> tableController = managerFactory.tableManager().getController(table.getId());
|
||||
if (!tableController.isPresent()) {
|
||||
logger.error("table not found : " + table.getId());
|
||||
} else if (tableController.get().isUserStillActive(userId)) {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package mage.server;
|
||||
|
||||
import mage.server.User.UserState;
|
||||
import mage.server.managers.UserManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.server.record.UserStats;
|
||||
import mage.server.record.UserStatsRepository;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
import mage.view.UserView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
@ -19,37 +20,43 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum UserManager {
|
||||
instance;
|
||||
public class UserManagerImpl implements UserManager {
|
||||
|
||||
private static final int SERVER_TIMEOUTS_USER_INFORM_OPPONENTS_ABOUT_DISCONNECT_AFTER_SECS = 30; // send to chat info about disconnection troubles, must be more than ping timeout
|
||||
private static final int SERVER_TIMEOUTS_USER_DISCONNECT_FROM_SERVER_AFTER_SECS = 3 * 60; // removes from all games and chats too (can be seen in users list with disconnected status)
|
||||
private static final int SERVER_TIMEOUTS_USER_REMOVE_FROM_SERVER_AFTER_SECS = 8 * 60; // removes from users list
|
||||
|
||||
private static final Logger logger = Logger.getLogger(UserManager.class);
|
||||
private static final Logger logger = Logger.getLogger(UserManagerImpl.class);
|
||||
|
||||
protected final ScheduledExecutorService expireExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||
protected final ScheduledExecutorService userListExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
private List<UserView> userInfoList = new ArrayList<>();
|
||||
private final ManagerFactory managerFactory;
|
||||
|
||||
|
||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private final ConcurrentHashMap<UUID, User> users = new ConcurrentHashMap<>();
|
||||
|
||||
private static final ExecutorService USER_EXECUTOR = ThreadExecutor.instance.getCallExecutor();
|
||||
private ExecutorService USER_EXECUTOR;
|
||||
|
||||
UserManager() {
|
||||
public UserManagerImpl(ManagerFactory managerFactory) {
|
||||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
USER_EXECUTOR = managerFactory.threadExecutor().getCallExecutor();
|
||||
expireExecutor.scheduleAtFixedRate(this::checkExpired, 60, 60, TimeUnit.SECONDS);
|
||||
|
||||
userListExecutor.scheduleAtFixedRate(this::updateUserInfoList, 4, 4, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<User> createUser(String userName, String host, AuthorizedUser authorizedUser) {
|
||||
if (getUserByName(userName).isPresent()) {
|
||||
return Optional.empty(); //user already exists
|
||||
}
|
||||
User user = new User(userName, host, authorizedUser);
|
||||
User user = new User(managerFactory, userName, host, authorizedUser);
|
||||
final Lock w = lock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
|
@ -60,6 +67,7 @@ public enum UserManager {
|
|||
return Optional.of(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<User> getUser(UUID userId) {
|
||||
if (!users.containsKey(userId)) {
|
||||
//logger.warn(String.format("User with id %s could not be found", userId), new Throwable()); // TODO: remove after session freezes fixed
|
||||
|
@ -69,6 +77,7 @@ public enum UserManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<User> getUserByName(String userName) {
|
||||
final Lock r = lock.readLock();
|
||||
r.lock();
|
||||
|
@ -81,6 +90,7 @@ public enum UserManager {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<User> getUsers() {
|
||||
List<User> userList = new ArrayList<>();
|
||||
final Lock r = lock.readLock();
|
||||
|
@ -93,6 +103,7 @@ public enum UserManager {
|
|||
return userList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connectToSession(String sessionId, UUID userId) {
|
||||
if (userId != null) {
|
||||
User user = users.get(userId);
|
||||
|
@ -104,19 +115,19 @@ public enum UserManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(UUID userId, DisconnectReason reason) {
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = getUser(userId);
|
||||
if (user.isPresent()) {
|
||||
user.get().setSessionId("");
|
||||
if (reason == DisconnectReason.Disconnected) {
|
||||
removeUserFromAllTablesAndChat(userId, reason);
|
||||
user.get().setUserState(UserState.Offline);
|
||||
} else {
|
||||
// ChatManager.instance.sendLostConnectionMessage(userId, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdmin(UUID userId) {
|
||||
if (userId != null) {
|
||||
User user = users.get(userId);
|
||||
|
@ -127,6 +138,7 @@ public enum UserManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUserFromAllTablesAndChat(final UUID userId, final DisconnectReason reason) {
|
||||
if (userId != null) {
|
||||
getUser(userId).ifPresent(user
|
||||
|
@ -135,7 +147,7 @@ public enum UserManager {
|
|||
try {
|
||||
logger.info("USER REMOVE - " + user.getName() + " (" + reason.toString() + ") userId: " + userId + " [" + user.getGameInfo() + ']');
|
||||
user.removeUserFromAllTables(reason);
|
||||
ChatManager.instance.removeUser(user.getId(), reason);
|
||||
managerFactory.chatManager().removeUser(user.getId(), reason);
|
||||
logger.debug("USER REMOVE END - " + user.getName());
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
|
@ -146,13 +158,14 @@ public enum UserManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void informUserOpponents(final UUID userId, final String message) {
|
||||
if (userId != null) {
|
||||
getUser(userId).ifPresent(user
|
||||
-> USER_EXECUTOR.execute(
|
||||
() -> {
|
||||
try {
|
||||
ChatManager.instance.sendMessageToUserChats(user.getId(), message);
|
||||
managerFactory.chatManager().sendMessageToUserChats(user.getId(), message);
|
||||
} catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
|
@ -161,6 +174,7 @@ public enum UserManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean extendUserSession(UUID userId, String pingInfo) {
|
||||
if (userId != null) {
|
||||
User user = users.get(userId);
|
||||
|
@ -245,7 +259,7 @@ public enum UserManager {
|
|||
private void updateUserInfoList() {
|
||||
try {
|
||||
List<UserView> newUserInfoList = new ArrayList<>();
|
||||
for (User user : UserManager.instance.getUsers()) {
|
||||
for (User user : getUsers()) {
|
||||
newUserInfoList.add(new UserView(
|
||||
user.getName(),
|
||||
user.getHost(),
|
||||
|
@ -266,10 +280,12 @@ public enum UserManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserView> getUserInfoList() {
|
||||
return userInfoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleException(Exception ex) {
|
||||
if (ex != null) {
|
||||
logger.fatal("User manager exception ", ex);
|
||||
|
@ -281,6 +297,7 @@ public enum UserManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserHistory(String userName) {
|
||||
Optional<User> user = getUserByName(userName);
|
||||
if (user.isPresent()) {
|
||||
|
@ -295,6 +312,7 @@ public enum UserManager {
|
|||
return "User " + userName + " not found";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUserHistory() {
|
||||
USER_EXECUTOR.execute(() -> {
|
||||
for (String updatedUser : UserStatsRepository.instance.updateUserStats()) {
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
package mage.server.draft;
|
||||
|
||||
import mage.MageException;
|
||||
|
@ -9,10 +7,8 @@ import mage.game.events.Listener;
|
|||
import mage.game.events.PlayerQueryEvent;
|
||||
import mage.game.events.TableEvent;
|
||||
import mage.players.Player;
|
||||
import mage.server.TableManager;
|
||||
import mage.server.UserManager;
|
||||
import mage.server.game.GameController;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.view.DraftPickView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
@ -25,7 +21,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class DraftController {
|
||||
|
@ -33,6 +28,7 @@ public class DraftController {
|
|||
private static final Logger logger = Logger.getLogger(GameController.class);
|
||||
public static final String INIT_FILE_PATH = "config" + File.separator + "init.txt";
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final ConcurrentMap<UUID, DraftSession> draftSessions = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<UUID, UUID> userPlayerMap;
|
||||
private final UUID draftSessionId;
|
||||
|
@ -40,7 +36,8 @@ public class DraftController {
|
|||
private final UUID tableId;
|
||||
private final UUID markedCard;
|
||||
|
||||
public DraftController(Draft draft, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId) {
|
||||
public DraftController(ManagerFactory managerFactory, Draft draft, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId) {
|
||||
this.managerFactory = managerFactory;
|
||||
draftSessionId = UUID.randomUUID();
|
||||
this.userPlayerMap = userPlayerMap;
|
||||
this.draft = draft;
|
||||
|
@ -61,8 +58,7 @@ public class DraftController {
|
|||
endDraft();
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (MageException ex) {
|
||||
} catch (MageException ex) {
|
||||
logger.fatal("Table event listener error", ex);
|
||||
}
|
||||
}
|
||||
|
@ -75,13 +71,12 @@ public class DraftController {
|
|||
pickCard(event.getPlayerId(), event.getMax());
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (MageException ex) {
|
||||
} catch (MageException ex) {
|
||||
logger.fatal("Table event listener error", ex);
|
||||
}
|
||||
}
|
||||
);
|
||||
for (DraftPlayer player: draft.getPlayers()) {
|
||||
for (DraftPlayer player : draft.getPlayers()) {
|
||||
if (!player.getPlayer().isHuman()) {
|
||||
player.setJoined();
|
||||
logger.debug("player " + player.getPlayer().getId() + " has joined draft " + draft.getId());
|
||||
|
@ -96,13 +91,13 @@ public class DraftController {
|
|||
|
||||
public void join(UUID userId) {
|
||||
UUID playerId = userPlayerMap.get(userId);
|
||||
DraftSession draftSession = new DraftSession(draft, userId, playerId);
|
||||
DraftSession draftSession = new DraftSession(managerFactory, draft, userId, playerId);
|
||||
draftSessions.put(playerId, draftSession);
|
||||
UserManager.instance.getUser(userId).ifPresent(user-> {
|
||||
user.addDraft(playerId, draftSession);
|
||||
logger.debug("User " + user.getName() + " has joined draft " + draft.getId());
|
||||
draft.getPlayer(playerId).setJoined();
|
||||
});
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
user.addDraft(playerId, draftSession);
|
||||
logger.debug("User " + user.getName() + " has joined draft " + draft.getId());
|
||||
draft.getPlayer(playerId).setJoined();
|
||||
});
|
||||
checkStart();
|
||||
}
|
||||
|
||||
|
@ -114,7 +109,7 @@ public class DraftController {
|
|||
}
|
||||
|
||||
public boolean replacePlayer(Player oldPlayer, Player newPlayer) {
|
||||
if (draft.replacePlayer(oldPlayer, newPlayer)) {
|
||||
if (draft.replacePlayer(oldPlayer, newPlayer)) {
|
||||
DraftSession draftSession = draftSessions.get(oldPlayer.getId());
|
||||
if (draftSession != null) {
|
||||
draftSession.draftOver(); // closes the draft panel of the replaced player
|
||||
|
@ -128,12 +123,12 @@ public class DraftController {
|
|||
private synchronized void checkStart() {
|
||||
if (!draft.isStarted() && allJoined()) {
|
||||
draft.setStarted();
|
||||
ThreadExecutor.instance.getCallExecutor().execute(this::startDraft);
|
||||
managerFactory.threadExecutor().getCallExecutor().execute(this::startDraft);
|
||||
}
|
||||
}
|
||||
|
||||
private void startDraft() {
|
||||
for (final Entry<UUID, DraftSession> entry: draftSessions.entrySet()) {
|
||||
for (final Entry<UUID, DraftSession> entry : draftSessions.entrySet()) {
|
||||
if (!entry.getValue().init()) {
|
||||
logger.fatal("Unable to initialize client for playerId " + entry.getKey());
|
||||
//TODO: generate client error message
|
||||
|
@ -147,7 +142,7 @@ public class DraftController {
|
|||
if (!draft.allJoined()) {
|
||||
return false;
|
||||
}
|
||||
for (DraftPlayer player: draft.getPlayers()) {
|
||||
for (DraftPlayer player : draft.getPlayers()) {
|
||||
if (player.getPlayer().isHuman() && !draftSessions.containsKey(player.getPlayer().getId())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -160,12 +155,12 @@ public class DraftController {
|
|||
}
|
||||
|
||||
private void endDraft() throws MageException {
|
||||
for (final DraftSession draftSession: draftSessions.values()) {
|
||||
for (final DraftSession draftSession : draftSessions.values()) {
|
||||
draftSession.draftOver();
|
||||
draftSession.removeDraft();
|
||||
}
|
||||
TableManager.instance.endDraft(tableId, draft);
|
||||
DraftManager.instance.removeDraft(draft.getId());
|
||||
managerFactory.tableManager().endDraft(tableId, draft);
|
||||
managerFactory.draftManager().removeDraft(draft.getId());
|
||||
}
|
||||
|
||||
public void kill(UUID userId) {
|
||||
|
@ -210,7 +205,7 @@ public class DraftController {
|
|||
}
|
||||
|
||||
private synchronized void updateDraft() throws MageException {
|
||||
for (final Entry<UUID, DraftSession> entry: draftSessions.entrySet()) {
|
||||
for (final Entry<UUID, DraftSession> entry : draftSessions.entrySet()) {
|
||||
entry.getValue().update();
|
||||
}
|
||||
}
|
||||
|
@ -229,7 +224,7 @@ public class DraftController {
|
|||
draft.setAbort(true);
|
||||
try {
|
||||
endDraft();
|
||||
} catch(MageException ex) {
|
||||
} catch (MageException ex) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,69 +1,83 @@
|
|||
|
||||
|
||||
package mage.server.draft;
|
||||
|
||||
import mage.game.draft.Draft;
|
||||
import mage.server.managers.DraftManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.view.DraftPickView;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import mage.game.draft.Draft;
|
||||
import mage.view.DraftPickView;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum DraftManager {
|
||||
instance;
|
||||
public class DraftManagerImpl implements DraftManager {
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final ConcurrentMap<UUID, DraftController> draftControllers = new ConcurrentHashMap<>();
|
||||
|
||||
public DraftManagerImpl(ManagerFactory managerFactory) {
|
||||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID createDraftSession(Draft draft, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId) {
|
||||
DraftController draftController = new DraftController(draft, userPlayerMap, tableId);
|
||||
DraftController draftController = new DraftController(managerFactory, draft, userPlayerMap, tableId);
|
||||
draftControllers.put(draft.getId(), draftController);
|
||||
return draftController.getSessionId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void joinDraft(UUID draftId, UUID userId) {
|
||||
draftControllers.get(draftId).join(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyChatSession(UUID gameId) {
|
||||
draftControllers.remove(gameId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DraftPickView sendCardPick(UUID draftId, UUID userId, UUID cardId, Set<UUID> hiddenCards) {
|
||||
return draftControllers.get(draftId).sendCardPick(userId, cardId, hiddenCards);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCardMark(UUID draftId, UUID userId, UUID cardId) {
|
||||
draftControllers.get(draftId).sendCardMark(userId, cardId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSession(UUID userId) {
|
||||
for (DraftController controller: draftControllers.values()) {
|
||||
for (DraftController controller : draftControllers.values()) {
|
||||
controller.kill(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kill(UUID draftId, UUID userId) {
|
||||
draftControllers.get(draftId).kill(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeout(UUID gameId, UUID userId) {
|
||||
draftControllers.get(gameId).timeout(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDraft(UUID draftId) {
|
||||
draftControllers.remove(draftId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DraftController getControllerByDraftId(UUID draftId) {
|
||||
return draftControllers.get(draftId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DraftController> getController(UUID tableId) {
|
||||
return draftControllers.values().stream().filter(controller -> controller.getTableId().equals(tableId)).findFirst();
|
||||
}
|
|
@ -1,6 +1,15 @@
|
|||
|
||||
package mage.server.draft;
|
||||
|
||||
import mage.game.draft.Draft;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.interfaces.callback.ClientCallbackMethod;
|
||||
import mage.server.User;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.view.DraftClientMessage;
|
||||
import mage.view.DraftPickView;
|
||||
import mage.view.DraftView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
@ -8,16 +17,6 @@ import java.util.UUID;
|
|||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import mage.game.draft.Draft;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.interfaces.callback.ClientCallbackMethod;
|
||||
import mage.server.User;
|
||||
import mage.server.UserManager;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
import mage.view.DraftClientMessage;
|
||||
import mage.view.DraftPickView;
|
||||
import mage.view.DraftView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -26,6 +25,7 @@ public class DraftSession {
|
|||
|
||||
protected static final Logger logger = Logger.getLogger(DraftSession.class);
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
protected final UUID userId;
|
||||
protected final UUID playerId;
|
||||
protected final Draft draft;
|
||||
|
@ -33,9 +33,11 @@ public class DraftSession {
|
|||
protected UUID markedCard;
|
||||
|
||||
private ScheduledFuture<?> futureTimeout;
|
||||
protected static final ScheduledExecutorService timeoutExecutor = ThreadExecutor.instance.getTimeoutExecutor();
|
||||
protected final ScheduledExecutorService timeoutExecutor;
|
||||
|
||||
public DraftSession(Draft draft, UUID userId, UUID playerId) {
|
||||
public DraftSession(ManagerFactory managerFactory, Draft draft, UUID userId, UUID playerId) {
|
||||
this.managerFactory = managerFactory;
|
||||
this.timeoutExecutor = managerFactory.threadExecutor().getTimeoutExecutor();
|
||||
this.userId = userId;
|
||||
this.draft = draft;
|
||||
this.playerId = playerId;
|
||||
|
@ -44,12 +46,12 @@ public class DraftSession {
|
|||
|
||||
public boolean init() {
|
||||
if (!killed) {
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
if (user.isPresent()) {
|
||||
if (futureTimeout != null && !futureTimeout.isDone()) {
|
||||
int remaining = (int) futureTimeout.getDelay(TimeUnit.SECONDS);
|
||||
user.get().fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_INIT, draft.getId(),
|
||||
new DraftClientMessage(getDraftView(), getDraftPickView(remaining))));
|
||||
new DraftClientMessage(getDraftView(), getDraftPickView(remaining))));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -59,16 +61,16 @@ public class DraftSession {
|
|||
|
||||
public void update() {
|
||||
if (!killed) {
|
||||
UserManager.instance
|
||||
managerFactory.userManager()
|
||||
.getUser(userId).
|
||||
ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_UPDATE, draft.getId(),
|
||||
new DraftClientMessage(getDraftView(), null))));
|
||||
new DraftClientMessage(getDraftView(), null))));
|
||||
}
|
||||
}
|
||||
|
||||
public void draftOver() {
|
||||
if (!killed) {
|
||||
UserManager.instance
|
||||
managerFactory.userManager()
|
||||
.getUser(userId)
|
||||
.ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_OVER, draft.getId())));
|
||||
}
|
||||
|
@ -77,10 +79,10 @@ public class DraftSession {
|
|||
public void pickCard(int timeout) {
|
||||
if (!killed) {
|
||||
setupTimeout(timeout);
|
||||
UserManager.instance
|
||||
managerFactory.userManager()
|
||||
.getUser(userId)
|
||||
.ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_PICK, draft.getId(),
|
||||
new DraftClientMessage(getDraftView(), getDraftPickView(timeout)))));
|
||||
new DraftClientMessage(getDraftView(), getDraftPickView(timeout)))));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +91,7 @@ public class DraftSession {
|
|||
cancelTimeout();
|
||||
if (seconds > 0) {
|
||||
futureTimeout = timeoutExecutor.schedule(
|
||||
() -> DraftManager.instance.timeout(draft.getId(), userId),
|
||||
() -> managerFactory.draftManager().timeout(draft.getId(), userId),
|
||||
seconds, TimeUnit.SECONDS
|
||||
);
|
||||
}
|
||||
|
@ -103,7 +105,7 @@ public class DraftSession {
|
|||
|
||||
protected void handleRemoteException(RemoteException ex) {
|
||||
logger.fatal("DraftSession error ", ex);
|
||||
DraftManager.instance.kill(draft.getId(), userId);
|
||||
managerFactory.draftManager().kill(draft.getId(), userId);
|
||||
}
|
||||
|
||||
public void setKilled() {
|
||||
|
@ -119,7 +121,7 @@ public class DraftSession {
|
|||
}
|
||||
|
||||
public void removeDraft() {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.removeDraft(playerId));
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> user.removeDraft(playerId));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -23,11 +23,11 @@ import mage.game.permanent.Permanent;
|
|||
import mage.game.turn.Phase;
|
||||
import mage.interfaces.Action;
|
||||
import mage.players.Player;
|
||||
import mage.server.*;
|
||||
import mage.server.util.ConfigSettings;
|
||||
import mage.server.Main;
|
||||
import mage.server.User;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.server.util.Splitter;
|
||||
import mage.server.util.SystemUtil;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
import mage.utils.StreamUtils;
|
||||
import mage.utils.timer.PriorityTimer;
|
||||
import mage.view.*;
|
||||
|
@ -53,13 +53,14 @@ public class GameController implements GameCallback {
|
|||
private static final int GAME_TIMEOUTS_CHECK_JOINING_STATUS_EVERY_SECS = 10; // checks and inform players about joining status
|
||||
private static final int GAME_TIMEOUTS_CANCEL_PLAYER_GAME_JOINING_AFTER_INACTIVE_SECS = 2 * 60; // leave player from game if it don't join and inactive on server
|
||||
|
||||
private static final ExecutorService gameExecutor = ThreadExecutor.instance.getGameExecutor();
|
||||
private final ExecutorService gameExecutor;
|
||||
private static final Logger logger = Logger.getLogger(GameController.class);
|
||||
|
||||
protected final ScheduledExecutorService joinWaitingExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
private ScheduledFuture<?> futureTimeout;
|
||||
protected static final ScheduledExecutorService timeoutIdleExecutor = ThreadExecutor.instance.getTimeoutIdleExecutor();
|
||||
private final ManagerFactory managerFactory;
|
||||
protected final ScheduledExecutorService timeoutIdleExecutor;
|
||||
|
||||
private final ConcurrentMap<UUID, GameSessionPlayer> gameSessions = new ConcurrentHashMap<>();
|
||||
private final ReadWriteLock gameSessionsLock = new ReentrantReadWriteLock();
|
||||
|
@ -83,13 +84,16 @@ public class GameController implements GameCallback {
|
|||
private int turnsToRollback;
|
||||
private int requestsOpen;
|
||||
|
||||
public GameController(Game game, ConcurrentMap<UUID, UUID> userPlayerMap, UUID tableId, UUID choosingPlayerId, GameOptions gameOptions) {
|
||||
public GameController(ManagerFactory managerFactory, Game game, ConcurrentMap<UUID, UUID> userPlayerMap, UUID tableId, UUID choosingPlayerId, GameOptions gameOptions) {
|
||||
this.managerFactory = managerFactory;
|
||||
gameExecutor = managerFactory.threadExecutor().getGameExecutor();
|
||||
timeoutIdleExecutor = managerFactory.threadExecutor().getTimeoutIdleExecutor();
|
||||
gameSessionId = UUID.randomUUID();
|
||||
this.userPlayerMap = userPlayerMap;
|
||||
chatId = ChatManager.instance.createChatSession("Game " + game.getId());
|
||||
chatId = managerFactory.chatManager().createChatSession("Game " + game.getId());
|
||||
this.userReqestingRollback = null;
|
||||
this.game = game;
|
||||
this.game.setSaveGame(ConfigSettings.instance.isSaveGameActivated());
|
||||
this.game.setSaveGame(managerFactory.configSettings().isSaveGameActivated());
|
||||
this.tableId = tableId;
|
||||
this.choosingPlayerId = choosingPlayerId;
|
||||
this.gameOptions = gameOptions;
|
||||
|
@ -103,7 +107,7 @@ public class GameController implements GameCallback {
|
|||
for (GameSessionPlayer gameSessionPlayer : getGameSessions()) {
|
||||
gameSessionPlayer.cleanUp();
|
||||
}
|
||||
ChatManager.instance.destroyChatSession(chatId);
|
||||
managerFactory.chatManager().destroyChatSession(chatId);
|
||||
for (PriorityTimer priorityTimer : timers.values()) {
|
||||
priorityTimer.cancel();
|
||||
}
|
||||
|
@ -120,11 +124,11 @@ public class GameController implements GameCallback {
|
|||
updateGame();
|
||||
break;
|
||||
case INFO:
|
||||
ChatManager.instance.broadcast(chatId, "", event.getMessage(), MessageColor.BLACK, true, event.getGame(), MessageType.GAME, null);
|
||||
managerFactory.chatManager().broadcast(chatId, "", event.getMessage(), MessageColor.BLACK, true, event.getGame(), MessageType.GAME, null);
|
||||
logger.trace(game.getId() + " " + event.getMessage());
|
||||
break;
|
||||
case STATUS:
|
||||
ChatManager.instance.broadcast(chatId, "", event.getMessage(), MessageColor.ORANGE, event.getWithTime(), event.getWithTurnInfo() ? event.getGame() : null, MessageType.GAME, null);
|
||||
managerFactory.chatManager().broadcast(chatId, "", event.getMessage(), MessageColor.ORANGE, event.getWithTime(), event.getWithTurnInfo() ? event.getGame() : null, MessageType.GAME, null);
|
||||
logger.trace(game.getId() + " " + event.getMessage());
|
||||
break;
|
||||
case ERROR:
|
||||
|
@ -273,7 +277,7 @@ public class GameController implements GameCallback {
|
|||
logger.fatal("- userId: " + userId);
|
||||
return;
|
||||
}
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
if (!user.isPresent()) {
|
||||
logger.fatal("User not found : " + userId);
|
||||
return;
|
||||
|
@ -286,7 +290,7 @@ public class GameController implements GameCallback {
|
|||
GameSessionPlayer gameSession = gameSessions.get(playerId);
|
||||
String joinType;
|
||||
if (gameSession == null) {
|
||||
gameSession = new GameSessionPlayer(game, userId, playerId);
|
||||
gameSession = new GameSessionPlayer(managerFactory, game, userId, playerId);
|
||||
final Lock w = gameSessionsLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
|
@ -300,7 +304,7 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
user.get().addGame(playerId, gameSession);
|
||||
logger.debug("Player " + player.getName() + ' ' + playerId + " has " + joinType + " gameId: " + game.getId());
|
||||
ChatManager.instance.broadcast(chatId, "", game.getPlayer(playerId).getLogName() + " has " + joinType + " the game", MessageColor.ORANGE, true, game, MessageType.GAME, null);
|
||||
managerFactory.chatManager().broadcast(chatId, "", game.getPlayer(playerId).getLogName() + " has " + joinType + " the game", MessageColor.ORANGE, true, game, MessageType.GAME, null);
|
||||
checkStart();
|
||||
}
|
||||
|
||||
|
@ -335,7 +339,7 @@ public class GameController implements GameCallback {
|
|||
// join the game because player has not joined or was removed because of disconnect
|
||||
String problemPlayerFixes;
|
||||
user.removeConstructing(player.getId());
|
||||
GameManager.instance.joinGame(game.getId(), user.getId());
|
||||
managerFactory.gameManager().joinGame(game.getId(), user.getId());
|
||||
logger.warn("Forced join of player " + player.getName() + " (" + user.getUserState() + ") to gameId: " + game.getId());
|
||||
if (user.isConnected()) {
|
||||
// init game session, see reconnect()
|
||||
|
@ -345,7 +349,7 @@ public class GameController implements GameCallback {
|
|||
logger.warn("Send forced game start event for player " + player.getName() + " in gameId: " + game.getId());
|
||||
user.ccGameStarted(session.getGameId(), player.getId());
|
||||
session.init();
|
||||
GameManager.instance.sendPlayerString(session.getGameId(), user.getId(), "");
|
||||
managerFactory.gameManager().sendPlayerString(session.getGameId(), user.getId(), "");
|
||||
} else {
|
||||
problemPlayerFixes = "leave on broken game session";
|
||||
logger.error("Can't find game session for forced join, leave it: player " + player.getName() + " in gameId: " + game.getId());
|
||||
|
@ -357,7 +361,7 @@ public class GameController implements GameCallback {
|
|||
player.leave();
|
||||
}
|
||||
|
||||
ChatManager.instance.broadcast(chatId, player.getName(), user.getPingInfo()
|
||||
managerFactory.chatManager().broadcast(chatId, player.getName(), user.getPingInfo()
|
||||
+ " is forced to join the game (waiting ends after "
|
||||
+ GAME_TIMEOUTS_CANCEL_PLAYER_GAME_JOINING_AFTER_INACTIVE_SECS
|
||||
+ " secs, applied fixes: " + problemPlayerFixes + ")",
|
||||
|
@ -382,7 +386,7 @@ public class GameController implements GameCallback {
|
|||
private Optional<User> getUserByPlayerId(UUID playerId) {
|
||||
for (Map.Entry<UUID, UUID> entry : userPlayerMap.entrySet()) {
|
||||
if (entry.getValue().equals(playerId)) {
|
||||
return UserManager.instance.getUser(entry.getKey());
|
||||
return managerFactory.userManager().getUser(entry.getKey());
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
|
@ -391,7 +395,7 @@ public class GameController implements GameCallback {
|
|||
private void checkStart() {
|
||||
if (allJoined()) {
|
||||
joinWaitingExecutor.shutdownNow();
|
||||
ThreadExecutor.instance.getCallExecutor().execute(this::startGame);
|
||||
managerFactory.threadExecutor().getCallExecutor().execute(this::startGame);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,14 +427,14 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
if (!isAllowedToWatch(userId)) {
|
||||
// Dont want people on our ignore list to stalk us
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
user.showUserMessage("Not allowed", "You are banned from watching this game");
|
||||
ChatManager.instance.broadcast(chatId, user.getName(), " tried to join, but is banned", MessageColor.BLUE, true, game, ChatMessage.MessageType.STATUS, null);
|
||||
managerFactory.chatManager().broadcast(chatId, user.getName(), " tried to join, but is banned", MessageColor.BLUE, true, game, ChatMessage.MessageType.STATUS, null);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
GameSessionWatcher gameWatcher = new GameSessionWatcher(userId, game, false);
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
GameSessionWatcher gameWatcher = new GameSessionWatcher(managerFactory.userManager(), userId, game, false);
|
||||
final Lock w = gameWatchersLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
|
@ -440,7 +444,7 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
gameWatcher.init();
|
||||
user.addGameWatchInfo(game.getId());
|
||||
ChatManager.instance.broadcast(chatId, user.getName(), " has started watching", MessageColor.BLUE, true, game, ChatMessage.MessageType.STATUS, null);
|
||||
managerFactory.chatManager().broadcast(chatId, user.getName(), " has started watching", MessageColor.BLUE, true, game, ChatMessage.MessageType.STATUS, null);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -453,8 +457,8 @@ public class GameController implements GameCallback {
|
|||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
ChatManager.instance.broadcast(chatId, user.getName(), " has stopped watching", MessageColor.BLUE, true, game, ChatMessage.MessageType.STATUS, null);
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
managerFactory.chatManager().broadcast(chatId, user.getName(), " has stopped watching", MessageColor.BLUE, true, game, ChatMessage.MessageType.STATUS, null);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -628,7 +632,7 @@ public class GameController implements GameCallback {
|
|||
gameSession.requestPermissionToSeeHandCards(userIdRequester);
|
||||
} else {
|
||||
// player does not allow the request
|
||||
UserManager.instance.getUser(userIdRequester).ifPresent(requester -> {
|
||||
managerFactory.userManager().getUser(userIdRequester).ifPresent(requester -> {
|
||||
requester.showUserMessage("Request to show hand cards", "Player " + grantingPlayer.getName() + " does not allow to request to show hand cards!");
|
||||
});
|
||||
}
|
||||
|
@ -640,7 +644,7 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
} else {
|
||||
// user can already see the cards
|
||||
UserManager.instance.getUser(userIdRequester).ifPresent(requester -> {
|
||||
managerFactory.userManager().getUser(userIdRequester).ifPresent(requester -> {
|
||||
requester.showUserMessage("Request to show hand cards", "You can see already the hand cards of player " + grantingPlayer.getName() + '!');
|
||||
});
|
||||
|
||||
|
@ -653,9 +657,9 @@ public class GameController implements GameCallback {
|
|||
Player viewLimitedDeckPlayer = game.getPlayer(userIdRequester);
|
||||
if (viewLimitedDeckPlayer != null) {
|
||||
if (viewLimitedDeckPlayer.isHuman()) {
|
||||
for (MatchPlayer p : TableManager.instance.getTable(tableId).getMatch().getPlayers()) {
|
||||
for (MatchPlayer p : managerFactory.tableManager().getTable(tableId).getMatch().getPlayers()) {
|
||||
if (p.getPlayer().getId().equals(userIdRequester)) {
|
||||
Optional<User> u = UserManager.instance.getUser(origId);
|
||||
Optional<User> u = managerFactory.userManager().getUser(origId);
|
||||
if (u.isPresent() && p.getDeck() != null) {
|
||||
u.get().ccViewLimitedDeck(p.getDeck(), tableId, requestsOpen, true);
|
||||
}
|
||||
|
@ -698,8 +702,8 @@ public class GameController implements GameCallback {
|
|||
if (player != null) {
|
||||
String sb = player.getLogName()
|
||||
+ " has timed out (player had priority and was not active for "
|
||||
+ ConfigSettings.instance.getMaxSecondsIdle() + " seconds ) - Auto concede.";
|
||||
ChatManager.instance.broadcast(chatId, "", sb, MessageColor.BLACK, true, game, MessageType.STATUS, null);
|
||||
+ managerFactory.configSettings().getMaxSecondsIdle() + " seconds ) - Auto concede.";
|
||||
managerFactory.chatManager().broadcast(chatId, "", sb, MessageColor.BLACK, true, game, MessageType.STATUS, null);
|
||||
game.idleTimeout(playerId);
|
||||
}
|
||||
}
|
||||
|
@ -712,7 +716,7 @@ public class GameController implements GameCallback {
|
|||
for (final GameSessionWatcher gameWatcher : getGameSessionWatchers()) {
|
||||
gameWatcher.gameOver(message);
|
||||
}
|
||||
TableManager.instance.endGame(tableId);
|
||||
managerFactory.tableManager().endGame(tableId);
|
||||
}
|
||||
|
||||
public UUID getSessionId() {
|
||||
|
@ -763,7 +767,7 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
|
||||
private synchronized void endGameInfo() {
|
||||
Table table = TableManager.instance.getTable(tableId);
|
||||
Table table = managerFactory.tableManager().getTable(tableId);
|
||||
if (table != null) {
|
||||
if (table.getMatch() != null) {
|
||||
for (final GameSessionPlayer gameSession : getGameSessions()) {
|
||||
|
@ -784,7 +788,7 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
|
||||
private synchronized void choosePile(UUID playerId, final String message, final List<? extends Card> pile1, final List<? extends Card> pile2) throws MageException {
|
||||
perform(playerId, playerId1 -> getGameSession(playerId1).choosePile(message, new CardsView(pile1), new CardsView(pile2)));
|
||||
perform(playerId, playerId1 -> getGameSession(playerId1).choosePile(message, new CardsView(game, pile1), new CardsView(game, pile2)));
|
||||
}
|
||||
|
||||
private synchronized void chooseMode(UUID playerId, final Map<UUID, String> modes, final String message) throws MageException {
|
||||
|
@ -1012,7 +1016,7 @@ public class GameController implements GameCallback {
|
|||
cancelTimeout();
|
||||
futureTimeout = timeoutIdleExecutor.schedule(
|
||||
() -> idleTimeout(playerId),
|
||||
Main.isTestMode() ? 3600 : ConfigSettings.instance.getMaxSecondsIdle(),
|
||||
Main.isTestMode() ? 3600 : managerFactory.configSettings().getMaxSecondsIdle(),
|
||||
TimeUnit.SECONDS
|
||||
);
|
||||
}
|
||||
|
@ -1094,7 +1098,7 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
|
||||
public boolean isAllowedToWatch(UUID userId) {
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
if (user.isPresent()) {
|
||||
return !gameOptions.bannedUsers.contains(user.get().getName());
|
||||
}
|
||||
|
@ -1208,7 +1212,7 @@ public class GameController implements GameCallback {
|
|||
public String getPingsInfo() {
|
||||
List<String> usersInfo = new ArrayList<>();
|
||||
for (Map.Entry<UUID, UUID> entry : userPlayerMap.entrySet()) {
|
||||
Optional<User> user = UserManager.instance.getUser(entry.getKey());
|
||||
Optional<User> user = managerFactory.userManager().getUser(entry.getKey());
|
||||
user.ifPresent(u -> usersInfo.add("* " + u.getName() + ": " + u.getPingInfo()));
|
||||
}
|
||||
Collections.sort(usersInfo);
|
||||
|
@ -1216,7 +1220,7 @@ public class GameController implements GameCallback {
|
|||
|
||||
List<String> watchersinfo = new ArrayList<>();
|
||||
for (Map.Entry<UUID, GameSessionWatcher> entry : watchers.entrySet()) {
|
||||
Optional<User> user = UserManager.instance.getUser(entry.getValue().userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(entry.getValue().userId);
|
||||
user.ifPresent(u -> watchersinfo.add("* " + u.getName() + ": " + u.getPingInfo()));
|
||||
}
|
||||
Collections.sort(watchersinfo);
|
||||
|
|
|
@ -5,6 +5,8 @@ import mage.constants.ManaType;
|
|||
import mage.constants.PlayerAction;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameOptions;
|
||||
import mage.server.managers.GameManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.view.GameView;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -20,14 +22,19 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum GameManager {
|
||||
instance;
|
||||
public class GameManagerImpl implements GameManager {
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final ConcurrentMap<UUID, GameController> gameControllers = new ConcurrentHashMap<>();
|
||||
private final ReadWriteLock gameControllersLock = new ReentrantReadWriteLock();
|
||||
|
||||
public GameManagerImpl(ManagerFactory managerFactory) {
|
||||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID createGameSession(Game game, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId, UUID choosingPlayerId, GameOptions gameOptions) {
|
||||
GameController gameController = new GameController(game, userPlayerMap, tableId, choosingPlayerId, gameOptions);
|
||||
GameController gameController = new GameController(managerFactory, game, userPlayerMap, tableId, choosingPlayerId, gameOptions);
|
||||
final Lock w = gameControllersLock.writeLock();
|
||||
w.lock();
|
||||
try {
|
||||
|
@ -48,6 +55,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void joinGame(UUID gameId, UUID userId) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -55,6 +63,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<UUID> getChatId(UUID gameId) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -63,6 +72,7 @@ public enum GameManager {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPlayerUUID(UUID gameId, UUID userId, UUID data) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -70,6 +80,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPlayerString(UUID gameId, UUID userId, String data) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -77,6 +88,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPlayerManaType(UUID gameId, UUID playerId, UUID userId, ManaType data) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -84,6 +96,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPlayerBoolean(UUID gameId, UUID userId, Boolean data) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -91,6 +104,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPlayerInteger(UUID gameId, UUID userId, Integer data) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -98,6 +112,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void quitMatch(UUID gameId, UUID userId) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -105,6 +120,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPlayerAction(PlayerAction playerAction, UUID gameId, UUID userId, Object data) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -112,6 +128,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean watchGame(UUID gameId, UUID userId) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -120,6 +137,7 @@ public enum GameManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopWatching(UUID gameId, UUID userId) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -127,6 +145,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cheat(UUID gameId, UUID userId, UUID playerId, DeckCardLists deckList) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -134,6 +153,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cheat(UUID gameId, UUID userId, UUID playerId, String cardName) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -142,6 +162,7 @@ public enum GameManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGame(UUID gameId) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -156,6 +177,7 @@ public enum GameManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveGame(UUID gameId) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -164,6 +186,7 @@ public enum GameManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameView getGameView(UUID gameId, UUID playerId) {
|
||||
GameController gameController = getGameControllerSafe(gameId);
|
||||
if (gameController != null) {
|
||||
|
@ -172,10 +195,12 @@ public enum GameManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberActiveGames() {
|
||||
return getGameController().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, GameController> getGameController() {
|
||||
Map<UUID, GameController> newControllers = new HashMap<>();
|
||||
final Lock r = gameControllersLock.readLock();
|
|
@ -11,8 +11,8 @@ import mage.interfaces.callback.ClientCallback;
|
|||
import mage.interfaces.callback.ClientCallbackMethod;
|
||||
import mage.players.Player;
|
||||
import mage.server.User;
|
||||
import mage.server.UserManager;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
import mage.server.managers.UserManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.view.*;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
@ -28,12 +28,15 @@ public class GameSessionPlayer extends GameSessionWatcher {
|
|||
|
||||
private static final Logger logger = Logger.getLogger(GameSessionPlayer.class);
|
||||
|
||||
private final UserManager userManager;
|
||||
private final UUID playerId;
|
||||
|
||||
private static final ExecutorService callExecutor = ThreadExecutor.instance.getCallExecutor();
|
||||
private final ExecutorService callExecutor;
|
||||
|
||||
public GameSessionPlayer(Game game, UUID userId, UUID playerId) {
|
||||
super(userId, game, true);
|
||||
public GameSessionPlayer(ManagerFactory managerFactory, Game game, UUID userId, UUID playerId) {
|
||||
super(managerFactory.userManager(), userId, game, true);
|
||||
this.userManager = managerFactory.userManager();
|
||||
callExecutor = managerFactory.threadExecutor().getCallExecutor();
|
||||
this.playerId = playerId;
|
||||
}
|
||||
|
||||
|
@ -44,14 +47,14 @@ public class GameSessionPlayer extends GameSessionWatcher {
|
|||
|
||||
public void ask(final String question, final Map<String, Serializable> options) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_ASK, game.getId(), new GameClientMessage(getGameView(), question, options)))
|
||||
userManager.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_ASK, game.getId(), new GameClientMessage(getGameView(), question, options)))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void target(final String question, final CardsView cardView, final Set<UUID> targets, final boolean required, final Map<String, Serializable> options) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
userManager.getUser(userId).ifPresent(user -> {
|
||||
user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_TARGET, game.getId(), new GameClientMessage(getGameView(), question, cardView, targets, required, options)));
|
||||
});
|
||||
|
||||
|
@ -60,13 +63,13 @@ public class GameSessionPlayer extends GameSessionWatcher {
|
|||
|
||||
public void select(final String message, final Map<String, Serializable> options) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_SELECT, game.getId(), new GameClientMessage(getGameView(), message, options))));
|
||||
userManager.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_SELECT, game.getId(), new GameClientMessage(getGameView(), message, options))));
|
||||
}
|
||||
}
|
||||
|
||||
public void chooseAbility(final AbilityPickerView abilities) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user
|
||||
userManager.getUser(userId).ifPresent(user
|
||||
-> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_CHOOSE_ABILITY, game.getId(), abilities)));
|
||||
}
|
||||
|
||||
|
@ -74,7 +77,7 @@ public class GameSessionPlayer extends GameSessionWatcher {
|
|||
|
||||
public void choosePile(final String message, final CardsView pile1, final CardsView pile2) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user
|
||||
userManager.getUser(userId).ifPresent(user
|
||||
-> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_CHOOSE_PILE, game.getId(), new GameClientMessage(message, pile1, pile2))));
|
||||
}
|
||||
|
||||
|
@ -82,7 +85,7 @@ public class GameSessionPlayer extends GameSessionWatcher {
|
|||
|
||||
public void chooseChoice(final Choice choice) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user
|
||||
userManager.getUser(userId).ifPresent(user
|
||||
-> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_CHOOSE_CHOICE, game.getId(), new GameClientMessage(choice))));
|
||||
}
|
||||
|
||||
|
@ -90,14 +93,14 @@ public class GameSessionPlayer extends GameSessionWatcher {
|
|||
|
||||
public void playMana(final String message, final Map<String, Serializable> options) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user
|
||||
userManager.getUser(userId).ifPresent(user
|
||||
-> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_PLAY_MANA, game.getId(), new GameClientMessage(getGameView(), message, options))));
|
||||
}
|
||||
}
|
||||
|
||||
public void playXMana(final String message) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user
|
||||
userManager.getUser(userId).ifPresent(user
|
||||
-> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_PLAY_XMANA, game.getId(), new GameClientMessage(getGameView(), message))));
|
||||
|
||||
}
|
||||
|
@ -105,7 +108,7 @@ public class GameSessionPlayer extends GameSessionWatcher {
|
|||
|
||||
public void getAmount(final String message, final int min, final int max) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
userManager.getUser(userId).ifPresent(user -> {
|
||||
user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_GET_AMOUNT, game.getId(), new GameClientMessage(message, min, max)));
|
||||
});
|
||||
}
|
||||
|
@ -113,15 +116,15 @@ public class GameSessionPlayer extends GameSessionWatcher {
|
|||
|
||||
public void endGameInfo(Table table) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.END_GAME_INFO, game.getId(), getGameEndView(playerId, table))));
|
||||
userManager.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.END_GAME_INFO, game.getId(), getGameEndView(playerId, table))));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void requestPermissionToRollbackTurn(UUID requestingUserId, int numberTurns) {
|
||||
if (!killed) {
|
||||
Optional<User> requestingUser = UserManager.instance.getUser(requestingUserId);
|
||||
Optional<User> requestedUser = UserManager.instance.getUser(userId);
|
||||
Optional<User> requestingUser = userManager.getUser(requestingUserId);
|
||||
Optional<User> requestedUser = userManager.getUser(userId);
|
||||
if (requestedUser.isPresent() && requestingUser.isPresent()) {
|
||||
String message;
|
||||
switch (numberTurns) {
|
||||
|
@ -147,8 +150,8 @@ public class GameSessionPlayer extends GameSessionWatcher {
|
|||
|
||||
public void requestPermissionToSeeHandCards(UUID watcherId) {
|
||||
if (!killed) {
|
||||
Optional<User> watcher = UserManager.instance.getUser(watcherId);
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> watcher = userManager.getUser(watcherId);
|
||||
Optional<User> user = userManager.getUser(userId);
|
||||
if (user.isPresent() && watcher.isPresent()) {
|
||||
UserRequestMessage userRequestMessage = new UserRequestMessage(
|
||||
"User request",
|
||||
|
@ -217,7 +220,7 @@ public class GameSessionPlayer extends GameSessionWatcher {
|
|||
}
|
||||
|
||||
public void removeGame() {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.removeGame(playerId));
|
||||
userManager.getUser(userId).ifPresent(user -> user.removeGame(playerId));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import mage.interfaces.callback.ClientCallback;
|
|||
import mage.interfaces.callback.ClientCallbackMethod;
|
||||
import mage.players.Player;
|
||||
import mage.server.User;
|
||||
import mage.server.UserManager;
|
||||
import mage.server.managers.UserManager;
|
||||
import mage.view.GameClientMessage;
|
||||
import mage.view.GameEndView;
|
||||
import mage.view.GameView;
|
||||
|
@ -25,12 +25,14 @@ public class GameSessionWatcher {
|
|||
|
||||
protected static final Logger logger = Logger.getLogger(GameSessionWatcher.class);
|
||||
|
||||
private final UserManager userManager;
|
||||
protected final UUID userId;
|
||||
protected final Game game;
|
||||
protected boolean killed = false;
|
||||
protected final boolean isPlayer;
|
||||
|
||||
public GameSessionWatcher(UUID userId, Game game, boolean isPlayer) {
|
||||
public GameSessionWatcher(UserManager userManager, UUID userId, Game game, boolean isPlayer) {
|
||||
this.userManager = userManager;
|
||||
this.userId = userId;
|
||||
this.game = game;
|
||||
this.isPlayer = isPlayer;
|
||||
|
@ -38,7 +40,7 @@ public class GameSessionWatcher {
|
|||
|
||||
public boolean init() {
|
||||
if (!killed) {
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = userManager.getUser(userId);
|
||||
if (user.isPresent()) {
|
||||
user.get().fireCallback(new ClientCallback(ClientCallbackMethod.GAME_INIT, game.getId(), getGameView()));
|
||||
return true;
|
||||
|
@ -49,28 +51,28 @@ public class GameSessionWatcher {
|
|||
|
||||
public void update() {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_UPDATE, game.getId(), getGameView())));
|
||||
userManager.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_UPDATE, game.getId(), getGameView())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void inform(final String message) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_INFORM, game.getId(), new GameClientMessage(getGameView(), message))));
|
||||
userManager.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_INFORM, game.getId(), new GameClientMessage(getGameView(), message))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void informPersonal(final String message) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_INFORM_PERSONAL, game.getId(), new GameClientMessage(getGameView(), message))));
|
||||
userManager.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_INFORM_PERSONAL, game.getId(), new GameClientMessage(getGameView(), message))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void gameOver(final String message) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
userManager.getUser(userId).ifPresent(user -> {
|
||||
user.removeGameWatchInfo(game.getId());
|
||||
user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_OVER, game.getId(), message));
|
||||
});
|
||||
|
@ -86,7 +88,7 @@ public class GameSessionWatcher {
|
|||
|
||||
public void gameError(final String message) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_ERROR, game.getId(), message)));
|
||||
userManager.getUser(userId).ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.GAME_ERROR, game.getId(), message)));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
|
||||
package mage.server.game;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import mage.MageException;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.constants.TableState;
|
||||
|
@ -16,18 +9,21 @@ import mage.game.match.MatchOptions;
|
|||
import mage.game.tournament.TournamentOptions;
|
||||
import mage.players.PlayerType;
|
||||
import mage.server.RoomImpl;
|
||||
import mage.server.TableManager;
|
||||
import mage.server.User;
|
||||
import mage.server.UserManager;
|
||||
import mage.server.tournament.TournamentManager;
|
||||
import mage.server.util.ConfigSettings;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.view.MatchView;
|
||||
import mage.view.RoomUsersView;
|
||||
import mage.view.TableView;
|
||||
import mage.view.UsersView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
@ -40,9 +36,12 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
private static List<MatchView> matchView = new ArrayList<>();
|
||||
private static List<RoomUsersView> roomUsersView = new ArrayList<>();
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final ConcurrentHashMap<UUID, Table> tables = new ConcurrentHashMap<>();
|
||||
|
||||
public GamesRoomImpl() {
|
||||
public GamesRoomImpl(ManagerFactory managerFactory) {
|
||||
super(managerFactory.chatManager());
|
||||
this.managerFactory = managerFactory;
|
||||
UPDATE_EXECUTOR.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
update();
|
||||
|
@ -71,7 +70,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
} else {
|
||||
// more since 50 matches finished since this match so removeUserFromAllTablesAndChat it
|
||||
if (table.isTournament()) {
|
||||
TournamentManager.instance.removeTournament(table.getTournament().getId());
|
||||
managerFactory.tournamentManager().removeTournament(table.getTournament().getId());
|
||||
}
|
||||
this.removeTable(table.getId());
|
||||
}
|
||||
|
@ -79,7 +78,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
tableView = tableList;
|
||||
matchView = matchList;
|
||||
List<UsersView> users = new ArrayList<>();
|
||||
for (User user : UserManager.instance.getUsers()) {
|
||||
for (User user : managerFactory.userManager().getUsers()) {
|
||||
if (user.getUserState() != User.UserState.Offline && !user.getName().equals("Admin")) {
|
||||
try {
|
||||
users.add(new UsersView(user.getUserData().getFlagName(), user.getName(),
|
||||
|
@ -108,9 +107,9 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
users.sort((one, two) -> one.getUserName().compareToIgnoreCase(two.getUserName()));
|
||||
List<RoomUsersView> roomUserInfo = new ArrayList<>();
|
||||
roomUserInfo.add(new RoomUsersView(users,
|
||||
GameManager.instance.getNumberActiveGames(),
|
||||
ThreadExecutor.instance.getActiveThreads(ThreadExecutor.instance.getGameExecutor()),
|
||||
ConfigSettings.instance.getMaxGameThreads()
|
||||
managerFactory.gameManager().getNumberActiveGames(),
|
||||
managerFactory.threadExecutor().getActiveThreads(managerFactory.threadExecutor().getGameExecutor()),
|
||||
managerFactory.configSettings().getMaxGameThreads()
|
||||
));
|
||||
roomUsersView = roomUserInfo;
|
||||
}
|
||||
|
@ -123,7 +122,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
@Override
|
||||
public boolean joinTable(UUID userId, UUID tableId, String name, PlayerType playerType, int skill, DeckCardLists deckList, String password) throws MageException {
|
||||
if (tables.containsKey(tableId)) {
|
||||
return TableManager.instance.joinTable(userId, tableId, name, playerType, skill, deckList, password);
|
||||
return managerFactory.tableManager().joinTable(userId, tableId, name, playerType, skill, deckList, password);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -131,7 +130,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
|
||||
@Override
|
||||
public TableView createTable(UUID userId, MatchOptions options) {
|
||||
Table table = TableManager.instance.createTable(this.getRoomId(), userId, options);
|
||||
Table table = managerFactory.tableManager().createTable(this.getRoomId(), userId, options);
|
||||
tables.put(table.getId(), table);
|
||||
return new TableView(table);
|
||||
}
|
||||
|
@ -139,7 +138,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
@Override
|
||||
public boolean joinTournamentTable(UUID userId, UUID tableId, String name, PlayerType playerType, int skill, DeckCardLists deckList, String password) throws GameException {
|
||||
if (tables.containsKey(tableId)) {
|
||||
return TableManager.instance.joinTournament(userId, tableId, name, playerType, skill, deckList, password);
|
||||
return managerFactory.tableManager().joinTournament(userId, tableId, name, playerType, skill, deckList, password);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -147,7 +146,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
|
||||
@Override
|
||||
public TableView createTournamentTable(UUID userId, TournamentOptions options) {
|
||||
Table table = TableManager.instance.createTournamentTable(this.getRoomId(), userId, options);
|
||||
Table table = managerFactory.tableManager().createTournamentTable(this.getRoomId(), userId, options);
|
||||
tables.put(table.getId(), table);
|
||||
return new TableView(table);
|
||||
}
|
||||
|
@ -179,12 +178,12 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
|
||||
@Override
|
||||
public void leaveTable(UUID userId, UUID tableId) {
|
||||
TableManager.instance.leaveTable(userId, tableId);
|
||||
managerFactory.tableManager().leaveTable(userId, tableId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean watchTable(UUID userId, UUID tableId) throws MageException {
|
||||
return TableManager.instance.watchTable(userId, tableId);
|
||||
return managerFactory.tableManager().watchTable(userId, tableId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package mage.server.game;
|
||||
|
||||
import mage.server.managers.GamesRoomManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.Optional;
|
||||
|
@ -9,36 +11,44 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum GamesRoomManager {
|
||||
instance;
|
||||
public class GamesRoomManagerImpl implements GamesRoomManager {
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final ConcurrentHashMap<UUID, GamesRoom> rooms = new ConcurrentHashMap<>();
|
||||
private final UUID mainRoomId;
|
||||
private final UUID mainChatId;
|
||||
private static final Logger logger = Logger.getLogger(GamesRoomManager.class);
|
||||
private UUID mainRoomId;
|
||||
private UUID mainChatId;
|
||||
private static final Logger logger = Logger.getLogger(GamesRoomManagerImpl.class);
|
||||
|
||||
|
||||
GamesRoomManager() {
|
||||
GamesRoom mainRoom = new GamesRoomImpl();
|
||||
public GamesRoomManagerImpl(ManagerFactory managerFactory) {
|
||||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
GamesRoom mainRoom = new GamesRoomImpl(managerFactory);
|
||||
mainRoomId = mainRoom.getRoomId();
|
||||
mainChatId = mainRoom.getChatId();
|
||||
rooms.put(mainRoomId, mainRoom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID createRoom() {
|
||||
GamesRoom room = new GamesRoomImpl();
|
||||
GamesRoom room = new GamesRoomImpl(managerFactory);
|
||||
rooms.put(room.getRoomId(), room);
|
||||
return room.getRoomId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getMainRoomId() {
|
||||
return mainRoomId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getMainChatId() {
|
||||
return mainChatId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GamesRoom> getRoom(UUID roomId) {
|
||||
if (rooms.containsKey(roomId)) {
|
||||
return Optional.of(rooms.get(roomId));
|
||||
|
@ -48,6 +58,7 @@ public enum GamesRoomManager {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTable(UUID tableId) {
|
||||
for (GamesRoom room : rooms.values()) {
|
||||
room.removeTable(tableId);
|
|
@ -1,46 +1,56 @@
|
|||
|
||||
|
||||
package mage.server.game;
|
||||
|
||||
import mage.server.managers.ReplayManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import mage.server.UserManager;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum ReplayManager {
|
||||
instance;
|
||||
public class ReplayManagerImpl implements ReplayManager {
|
||||
|
||||
private final ConcurrentHashMap<String, ReplaySession> replaySessions = new ConcurrentHashMap<>();
|
||||
private final ManagerFactory managerFactory;
|
||||
|
||||
public void replayGame(UUID gameId, UUID userId) {
|
||||
ReplaySession replaySession = new ReplaySession(gameId, userId);
|
||||
replaySessions.put(gameId.toString() + userId.toString(), replaySession);
|
||||
UserManager.instance.getUser(userId).ifPresent(user->user.ccReplayGame(gameId));
|
||||
public ReplayManagerImpl(ManagerFactory managerFactory) {
|
||||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replayGame(UUID gameId, UUID userId) {
|
||||
ReplaySession replaySession = new ReplaySession(managerFactory, gameId, userId);
|
||||
replaySessions.put(gameId.toString() + userId.toString(), replaySession);
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> user.ccReplayGame(gameId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startReplay(UUID gameId, UUID userId) {
|
||||
replaySessions.get(gameId.toString() + userId.toString()).replay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopReplay(UUID gameId, UUID userId) {
|
||||
replaySessions.get(gameId.toString() + userId.toString()).stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextPlay(UUID gameId, UUID userId) {
|
||||
replaySessions.get(gameId.toString() + userId.toString()).next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void previousPlay(UUID gameId, UUID userId) {
|
||||
replaySessions.get(gameId.toString() + userId.toString()).previous();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skipForward(UUID gameId, UUID userId, int moves) {
|
||||
replaySessions.get(gameId.toString() + userId.toString()).next(moves);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endReplay(UUID gameId, UUID userId) {
|
||||
replaySessions.remove(gameId.toString() + userId.toString());
|
||||
}
|
|
@ -1,32 +1,32 @@
|
|||
|
||||
|
||||
package mage.server.game;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.game.Game;
|
||||
import mage.game.GameState;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.interfaces.callback.ClientCallbackMethod;
|
||||
import mage.server.UserManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.view.GameView;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class ReplaySession implements GameCallback {
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final GameReplay replay;
|
||||
protected final UUID userId;
|
||||
|
||||
ReplaySession(UUID gameId, UUID userId) {
|
||||
ReplaySession(ManagerFactory managerFactory, UUID gameId, UUID userId) {
|
||||
this.managerFactory = managerFactory;
|
||||
this.replay = new GameReplay(gameId);
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public void replay() {
|
||||
replay.start();
|
||||
UserManager.instance.getUser(userId).ifPresent(user ->
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user ->
|
||||
user.fireCallback(new ClientCallback(ClientCallbackMethod.REPLAY_INIT, replay.getGame().getId(), new GameView(replay.next(), replay.getGame(), null, null))));
|
||||
|
||||
}
|
||||
|
@ -52,17 +52,17 @@ public class ReplaySession implements GameCallback {
|
|||
|
||||
@Override
|
||||
public void gameResult(final String result) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user ->
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user ->
|
||||
user.fireCallback(new ClientCallback(ClientCallbackMethod.REPLAY_DONE, replay.getGame().getId(), result)));
|
||||
|
||||
ReplayManager.instance.endReplay(replay.getGame().getId(), userId);
|
||||
managerFactory.replayManager().endReplay(replay.getGame().getId(), userId);
|
||||
}
|
||||
|
||||
private void updateGame(final GameState state, Game game) {
|
||||
if (state == null) {
|
||||
gameResult("game ended");
|
||||
} else {
|
||||
UserManager.instance.getUser(userId).ifPresent(user ->
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user ->
|
||||
user.fireCallback(new ClientCallback(ClientCallbackMethod.REPLAY_UPDATE, replay.getGame().getId(), new GameView(state, game, null, null))));
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import mage.game.Game;
|
||||
import mage.server.ChatSession;
|
||||
import mage.server.DisconnectReason;
|
||||
import mage.server.exceptions.UserNotFoundException;
|
||||
import mage.view.ChatMessage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ChatManager {
|
||||
UUID createChatSession(String info);
|
||||
|
||||
void joinChat(UUID chatId, UUID userId);
|
||||
|
||||
void clearUserMessageStorage();
|
||||
|
||||
void leaveChat(UUID chatId, UUID userId);
|
||||
|
||||
void destroyChatSession(UUID chatId);
|
||||
|
||||
void broadcast(UUID chatId, String userName, String message, ChatMessage.MessageColor color, boolean withTime, Game game, ChatMessage.MessageType messageType, ChatMessage.SoundToPlay soundToPlay);
|
||||
|
||||
void broadcast(UUID userId, String message, ChatMessage.MessageColor color) throws UserNotFoundException;
|
||||
|
||||
void sendReconnectMessage(UUID userId);
|
||||
|
||||
void sendLostConnectionMessage(UUID userId, DisconnectReason reason);
|
||||
|
||||
void sendMessageToUserChats(UUID userId, String message);
|
||||
|
||||
void removeUser(UUID userId, DisconnectReason reason);
|
||||
|
||||
List<ChatSession> getChatSessions();
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import mage.server.util.config.GamePlugin;
|
||||
import mage.server.util.config.Plugin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ConfigSettings {
|
||||
String getServerAddress();
|
||||
|
||||
String getServerName();
|
||||
|
||||
int getPort();
|
||||
|
||||
int getSecondaryBindPort();
|
||||
|
||||
int getLeasePeriod();
|
||||
|
||||
int getSocketWriteTimeout();
|
||||
|
||||
int getMaxPoolSize();
|
||||
|
||||
int getNumAcceptThreads();
|
||||
|
||||
int getBacklogSize();
|
||||
|
||||
int getMaxGameThreads();
|
||||
|
||||
int getMaxSecondsIdle();
|
||||
|
||||
int getMinUserNameLength();
|
||||
|
||||
int getMaxUserNameLength();
|
||||
|
||||
String getInvalidUserNamePattern();
|
||||
|
||||
int getMinPasswordLength();
|
||||
|
||||
int getMaxPasswordLength();
|
||||
|
||||
String getMaxAiOpponents();
|
||||
|
||||
Boolean isSaveGameActivated();
|
||||
|
||||
Boolean isAuthenticationActivated();
|
||||
|
||||
String getGoogleAccount();
|
||||
|
||||
String getMailgunApiKey();
|
||||
|
||||
String getMailgunDomain();
|
||||
|
||||
String getMailSmtpHost();
|
||||
|
||||
String getMailSmtpPort();
|
||||
|
||||
String getMailUser();
|
||||
|
||||
String getMailPassword();
|
||||
|
||||
String getMailFromAddress();
|
||||
|
||||
List<Plugin> getPlayerTypes();
|
||||
|
||||
List<GamePlugin> getGameTypes();
|
||||
|
||||
List<GamePlugin> getTournamentTypes();
|
||||
|
||||
List<Plugin> getDraftCubes();
|
||||
|
||||
List<Plugin> getDeckTypes();
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import mage.game.draft.Draft;
|
||||
import mage.server.draft.DraftController;
|
||||
import mage.view.DraftPickView;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public interface DraftManager {
|
||||
UUID createDraftSession(Draft draft, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId);
|
||||
|
||||
void joinDraft(UUID draftId, UUID userId);
|
||||
|
||||
void destroyChatSession(UUID gameId);
|
||||
|
||||
DraftPickView sendCardPick(UUID draftId, UUID userId, UUID cardId, Set<UUID> hiddenCards);
|
||||
|
||||
void sendCardMark(UUID draftId, UUID userId, UUID cardId);
|
||||
|
||||
void removeSession(UUID userId);
|
||||
|
||||
void kill(UUID draftId, UUID userId);
|
||||
|
||||
void timeout(UUID gameId, UUID userId);
|
||||
|
||||
void removeDraft(UUID draftId);
|
||||
|
||||
DraftController getControllerByDraftId(UUID draftId);
|
||||
|
||||
Optional<DraftController> getController(UUID tableId);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.PlayerAction;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameOptions;
|
||||
import mage.server.game.GameController;
|
||||
import mage.view.GameView;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public interface GameManager {
|
||||
UUID createGameSession(Game game, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId, UUID choosingPlayerId, GameOptions gameOptions);
|
||||
|
||||
void joinGame(UUID gameId, UUID userId);
|
||||
|
||||
Optional<UUID> getChatId(UUID gameId);
|
||||
|
||||
void sendPlayerUUID(UUID gameId, UUID userId, UUID data);
|
||||
|
||||
void sendPlayerString(UUID gameId, UUID userId, String data);
|
||||
|
||||
void sendPlayerManaType(UUID gameId, UUID playerId, UUID userId, ManaType data);
|
||||
|
||||
void sendPlayerBoolean(UUID gameId, UUID userId, Boolean data);
|
||||
|
||||
void sendPlayerInteger(UUID gameId, UUID userId, Integer data);
|
||||
|
||||
void quitMatch(UUID gameId, UUID userId);
|
||||
|
||||
void sendPlayerAction(PlayerAction playerAction, UUID gameId, UUID userId, Object data);
|
||||
|
||||
boolean watchGame(UUID gameId, UUID userId);
|
||||
|
||||
void stopWatching(UUID gameId, UUID userId);
|
||||
|
||||
void cheat(UUID gameId, UUID userId, UUID playerId, DeckCardLists deckList);
|
||||
|
||||
boolean cheat(UUID gameId, UUID userId, UUID playerId, String cardName);
|
||||
|
||||
void removeGame(UUID gameId);
|
||||
|
||||
boolean saveGame(UUID gameId);
|
||||
|
||||
GameView getGameView(UUID gameId, UUID playerId);
|
||||
|
||||
int getNumberActiveGames();
|
||||
|
||||
Map<UUID, GameController> getGameController();
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import mage.server.game.GamesRoom;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface GamesRoomManager {
|
||||
UUID createRoom();
|
||||
|
||||
UUID getMainRoomId();
|
||||
|
||||
UUID getMainChatId();
|
||||
|
||||
Optional<GamesRoom> getRoom(UUID roomId);
|
||||
|
||||
void removeTable(UUID tableId);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package mage.server.managers;
|
||||
|
||||
public interface MailClient {
|
||||
|
||||
boolean sendMessage(String email, String subject, String text);
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package mage.server.managers;
|
||||
|
||||
public interface ManagerFactory {
|
||||
ChatManager chatManager();
|
||||
|
||||
DraftManager draftManager();
|
||||
|
||||
GameManager gameManager();
|
||||
|
||||
GamesRoomManager gamesRoomManager();
|
||||
|
||||
MailClient mailClient();
|
||||
|
||||
MailClient mailgunClient();
|
||||
|
||||
ReplayManager replayManager();
|
||||
|
||||
SessionManager sessionManager();
|
||||
|
||||
TableManager tableManager();
|
||||
|
||||
UserManager userManager();
|
||||
|
||||
ConfigSettings configSettings();
|
||||
|
||||
ThreadExecutor threadExecutor();
|
||||
|
||||
TournamentManager tournamentManager();
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ReplayManager {
|
||||
void replayGame(UUID gameId, UUID userId);
|
||||
|
||||
void startReplay(UUID gameId, UUID userId);
|
||||
|
||||
void stopReplay(UUID gameId, UUID userId);
|
||||
|
||||
void nextPlay(UUID gameId, UUID userId);
|
||||
|
||||
void previousPlay(UUID gameId, UUID userId);
|
||||
|
||||
void skipForward(UUID gameId, UUID userId, int moves);
|
||||
|
||||
void endReplay(UUID gameId, UUID userId);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import mage.MageException;
|
||||
import mage.players.net.UserData;
|
||||
import mage.server.DisconnectReason;
|
||||
import mage.server.Session;
|
||||
import mage.server.User;
|
||||
import org.jboss.remoting.callback.InvokerCallbackHandler;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface SessionManager {
|
||||
Optional<Session> getSession(@Nonnull String sessionId);
|
||||
|
||||
void createSession(String sessionId, InvokerCallbackHandler callbackHandler);
|
||||
|
||||
boolean registerUser(String sessionId, String userName, String password, String email) throws MageException;
|
||||
|
||||
boolean connectUser(String sessionId, String userName, String password, String userIdStr) throws MageException;
|
||||
|
||||
boolean connectAdmin(String sessionId);
|
||||
|
||||
boolean setUserData(String userName, String sessionId, UserData userData, String clientVersion, String userIdStr) throws MageException;
|
||||
|
||||
void disconnect(String sessionId, DisconnectReason reason);
|
||||
|
||||
void disconnect(String sessionId, DisconnectReason reason, Session directSession);
|
||||
|
||||
void disconnectUser(String sessionId, String userSessionId);
|
||||
|
||||
void endUserSession(String sessionId, String userSessionId);
|
||||
|
||||
boolean isAdmin(String sessionId);
|
||||
|
||||
boolean isValidSession(@Nonnull String sessionId);
|
||||
|
||||
Optional<User> getUser(@Nonnull String sessionId);
|
||||
|
||||
boolean extendUserSession(String sessionId, String pingInfo);
|
||||
|
||||
void sendErrorMessageToClient(String sessionId, String message);
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import mage.MageException;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.game.GameException;
|
||||
import mage.game.Table;
|
||||
import mage.game.draft.Draft;
|
||||
import mage.game.match.Match;
|
||||
import mage.game.match.MatchOptions;
|
||||
import mage.game.tournament.Tournament;
|
||||
import mage.game.tournament.TournamentOptions;
|
||||
import mage.game.tournament.TournamentPlayer;
|
||||
import mage.players.PlayerType;
|
||||
import mage.server.TableController;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface TableManager {
|
||||
Table createTable(UUID roomId, UUID userId, MatchOptions options);
|
||||
|
||||
Table createTable(UUID roomId, MatchOptions options);
|
||||
|
||||
Table createTournamentTable(UUID roomId, UUID userId, TournamentOptions options);
|
||||
|
||||
Table getTable(UUID tableId);
|
||||
|
||||
Optional<Match> getMatch(UUID tableId);
|
||||
|
||||
Collection<Table> getTables();
|
||||
|
||||
Collection<TableController> getControllers();
|
||||
|
||||
Optional<TableController> getController(UUID tableId);
|
||||
|
||||
boolean joinTable(UUID userId, UUID tableId, String name, PlayerType playerType, int skill, DeckCardLists deckList, String password) throws MageException;
|
||||
|
||||
boolean joinTournament(UUID userId, UUID tableId, String name, PlayerType playerType, int skill, DeckCardLists deckList, String password) throws GameException;
|
||||
|
||||
boolean submitDeck(UUID userId, UUID tableId, DeckCardLists deckList) throws MageException;
|
||||
|
||||
void updateDeck(UUID userId, UUID tableId, DeckCardLists deckList) throws MageException;
|
||||
|
||||
// removeUserFromAllTablesAndChat user from all tournament sub tables
|
||||
void userQuitTournamentSubTables(UUID userId);
|
||||
|
||||
// removeUserFromAllTablesAndChat user from all sub tables of a tournament
|
||||
void userQuitTournamentSubTables(UUID tournamentId, UUID userId);
|
||||
|
||||
boolean isTableOwner(UUID tableId, UUID userId);
|
||||
|
||||
boolean removeTable(UUID userId, UUID tableId);
|
||||
|
||||
void leaveTable(UUID userId, UUID tableId);
|
||||
|
||||
Optional<UUID> getChatId(UUID tableId);
|
||||
|
||||
void startMatch(UUID userId, UUID roomId, UUID tableId);
|
||||
|
||||
void startTournamentSubMatch(UUID roomId, UUID tableId);
|
||||
|
||||
void startTournament(UUID userId, UUID roomId, UUID tableId);
|
||||
|
||||
void startDraft(UUID tableId, Draft draft);
|
||||
|
||||
boolean watchTable(UUID userId, UUID tableId);
|
||||
|
||||
void endGame(UUID tableId);
|
||||
|
||||
void endDraft(UUID tableId, Draft draft);
|
||||
|
||||
void endTournament(UUID tableId, Tournament tournament);
|
||||
|
||||
void swapSeats(UUID tableId, UUID userId, int seatNum1, int seatNum2);
|
||||
|
||||
void construct(UUID tableId);
|
||||
|
||||
void initTournament(UUID tableId);
|
||||
|
||||
void addPlayer(UUID userId, UUID tableId, TournamentPlayer player) throws GameException;
|
||||
|
||||
void removeTable(UUID tableId);
|
||||
|
||||
void debugServerState();
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public interface ThreadExecutor {
|
||||
int getActiveThreads(ExecutorService executerService);
|
||||
|
||||
ExecutorService getCallExecutor();
|
||||
|
||||
ExecutorService getGameExecutor();
|
||||
|
||||
ScheduledExecutorService getTimeoutExecutor();
|
||||
|
||||
ScheduledExecutorService getTimeoutIdleExecutor();
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.game.tournament.Tournament;
|
||||
import mage.server.tournament.TournamentController;
|
||||
import mage.view.TournamentView;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public interface TournamentManager {
|
||||
Optional<TournamentController> getTournamentController(UUID tournamentId);
|
||||
|
||||
void createTournamentSession(Tournament tournament, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId);
|
||||
|
||||
void joinTournament(UUID tournamentId, UUID userId);
|
||||
|
||||
void quit(UUID tournamentId, UUID userId);
|
||||
|
||||
void timeout(UUID tournamentId, UUID userId);
|
||||
|
||||
void submitDeck(UUID tournamentId, UUID playerId, Deck deck);
|
||||
|
||||
boolean updateDeck(UUID tournamentId, UUID playerId, Deck deck);
|
||||
|
||||
TournamentView getTournamentView(UUID tournamentId);
|
||||
|
||||
Optional<UUID> getChatId(UUID tournamentId);
|
||||
|
||||
void removeTournament(UUID tournamentId);
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import mage.server.AuthorizedUser;
|
||||
import mage.server.DisconnectReason;
|
||||
import mage.server.User;
|
||||
import mage.view.UserView;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface UserManager {
|
||||
Optional<User> createUser(String userName, String host, AuthorizedUser authorizedUser);
|
||||
|
||||
Optional<User> getUser(UUID userId);
|
||||
|
||||
Optional<User> getUserByName(String userName);
|
||||
|
||||
Collection<User> getUsers();
|
||||
|
||||
boolean connectToSession(String sessionId, UUID userId);
|
||||
|
||||
void disconnect(UUID userId, DisconnectReason reason);
|
||||
|
||||
boolean isAdmin(UUID userId);
|
||||
|
||||
void removeUserFromAllTablesAndChat(UUID userId, DisconnectReason reason);
|
||||
|
||||
void informUserOpponents(UUID userId, String message);
|
||||
|
||||
boolean extendUserSession(UUID userId, String pingInfo);
|
||||
|
||||
List<UserView> getUserInfoList();
|
||||
|
||||
void handleException(Exception ex);
|
||||
|
||||
String getUserHistory(String userName);
|
||||
|
||||
void updateUserHistory();
|
||||
}
|
|
@ -3,16 +3,20 @@ package mage.server.record;
|
|||
import mage.game.Table;
|
||||
import mage.game.Table.TableRecorder;
|
||||
import mage.game.result.ResultProtos.TableProto;
|
||||
import mage.server.UserManager;
|
||||
import mage.server.managers.UserManager;
|
||||
|
||||
public enum TableRecorderImpl implements TableRecorder {
|
||||
public class TableRecorderImpl implements TableRecorder {
|
||||
|
||||
instance;
|
||||
private final UserManager userManager;
|
||||
|
||||
public TableRecorderImpl(UserManager userManager) {
|
||||
this.userManager = userManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void record(Table table) {
|
||||
TableProto proto = table.toProto();
|
||||
TableRecordRepository.instance.add(new TableRecord(proto, proto.getEndTimeMs()));
|
||||
UserManager.instance.updateUserHistory();
|
||||
userManager.updateUserHistory();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,14 +17,10 @@ import mage.game.tournament.Tournament;
|
|||
import mage.game.tournament.TournamentPairing;
|
||||
import mage.game.tournament.TournamentPlayer;
|
||||
import mage.players.PlayerType;
|
||||
import mage.server.ChatManager;
|
||||
import mage.server.TableManager;
|
||||
import mage.server.User;
|
||||
import mage.server.UserManager;
|
||||
import mage.server.draft.DraftController;
|
||||
import mage.server.draft.DraftManager;
|
||||
import mage.server.game.GamesRoomManager;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
import mage.server.managers.TableManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.view.ChatMessage.MessageColor;
|
||||
import mage.view.ChatMessage.MessageType;
|
||||
import mage.view.ChatMessage.SoundToPlay;
|
||||
|
@ -44,6 +40,7 @@ public class TournamentController {
|
|||
|
||||
private static final Logger logger = Logger.getLogger(TournamentController.class);
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final UUID chatId;
|
||||
private final UUID tableId;
|
||||
private boolean started = false;
|
||||
|
@ -51,9 +48,10 @@ public class TournamentController {
|
|||
private ConcurrentMap<UUID, UUID> userPlayerMap = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<UUID, TournamentSession> tournamentSessions = new ConcurrentHashMap<>();
|
||||
|
||||
public TournamentController(Tournament tournament, ConcurrentMap<UUID, UUID> userPlayerMap, UUID tableId) {
|
||||
public TournamentController(ManagerFactory managerFactory, Tournament tournament, ConcurrentMap<UUID, UUID> userPlayerMap, UUID tableId) {
|
||||
this.managerFactory = managerFactory;
|
||||
this.userPlayerMap = userPlayerMap;
|
||||
chatId = ChatManager.instance.createChatSession("Tournament " + tournament.getId());
|
||||
chatId = managerFactory.chatManager().createChatSession("Tournament " + tournament.getId());
|
||||
this.tournament = tournament;
|
||||
this.tableId = tableId;
|
||||
init();
|
||||
|
@ -67,7 +65,7 @@ public class TournamentController {
|
|||
checkPlayersState();
|
||||
break;
|
||||
case INFO:
|
||||
ChatManager.instance.broadcast(chatId, "", event.getMessage(), MessageColor.BLACK, true, null, MessageType.STATUS, null);
|
||||
managerFactory.chatManager().broadcast(chatId, "", event.getMessage(), MessageColor.BLACK, true, null, MessageType.STATUS, null);
|
||||
logger.debug(tournament.getId() + " " + event.getMessage());
|
||||
break;
|
||||
case START_DRAFT:
|
||||
|
@ -122,7 +120,7 @@ public class TournamentController {
|
|||
if (!player.getPlayer().isHuman()) {
|
||||
player.setJoined();
|
||||
logger.debug("player " + player.getPlayer().getId() + " has joined tournament " + tournament.getId());
|
||||
ChatManager.instance.broadcast(chatId, "", player.getPlayer().getLogName() + " has joined the tournament", MessageColor.BLACK, true, null, MessageType.STATUS, null);
|
||||
managerFactory.chatManager().broadcast(chatId, "", player.getPlayer().getLogName() + " has joined the tournament", MessageColor.BLACK, true, null, MessageType.STATUS, null);
|
||||
}
|
||||
}
|
||||
checkStart();
|
||||
|
@ -132,7 +130,7 @@ public class TournamentController {
|
|||
UUID playerId = userPlayerMap.get(userId);
|
||||
if (playerId == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user
|
||||
-> logger.debug(user.getName() + " shows tournament panel tournamentId: " + tournament.getId()));
|
||||
|
||||
}
|
||||
|
@ -143,16 +141,16 @@ public class TournamentController {
|
|||
return;
|
||||
}
|
||||
// first join of player
|
||||
TournamentSession tournamentSession = new TournamentSession(tournament, userId, tableId, playerId);
|
||||
TournamentSession tournamentSession = new TournamentSession(managerFactory, tournament, userId, tableId, playerId);
|
||||
tournamentSessions.put(playerId, tournamentSession);
|
||||
Optional<User> _user = UserManager.instance.getUser(userId);
|
||||
Optional<User> _user = managerFactory.userManager().getUser(userId);
|
||||
if (_user.isPresent()) {
|
||||
User user = _user.get();
|
||||
user.addTournament(playerId, tournament.getId());
|
||||
TournamentPlayer player = tournament.getPlayer(playerId);
|
||||
player.setJoined();
|
||||
logger.debug("player " + player.getPlayer().getName() + " - client has joined tournament " + tournament.getId());
|
||||
ChatManager.instance.broadcast(chatId, "", player.getPlayer().getLogName() + " has joined the tournament", MessageColor.BLACK, true, null, MessageType.STATUS, null);
|
||||
managerFactory.chatManager().broadcast(chatId, "", player.getPlayer().getLogName() + " has joined the tournament", MessageColor.BLACK, true, null, MessageType.STATUS, null);
|
||||
checkStart();
|
||||
} else {
|
||||
logger.error("User not found userId: " + userId + " tournamentId: " + tournament.getId());
|
||||
|
@ -174,7 +172,7 @@ public class TournamentController {
|
|||
|
||||
private void checkStart() {
|
||||
if (!started && allJoined()) {
|
||||
ThreadExecutor.instance.getCallExecutor().execute(this::startTournament);
|
||||
managerFactory.threadExecutor().getCallExecutor().execute(this::startTournament);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,15 +209,15 @@ public class TournamentController {
|
|||
tournamentSession.tournamentOver();
|
||||
}
|
||||
this.tournamentSessions.clear();
|
||||
TableManager.instance.endTournament(tableId, tournament);
|
||||
managerFactory.tableManager().endTournament(tableId, tournament);
|
||||
tournament.cleanUpOnTournamentEnd();
|
||||
|
||||
}
|
||||
|
||||
private void startMatch(TournamentPairing pair, MatchOptions matchOptions) {
|
||||
try {
|
||||
TableManager tableManager = TableManager.instance;
|
||||
Table table = tableManager.createTable(GamesRoomManager.instance.getMainRoomId(), matchOptions);
|
||||
TableManager tableManager = managerFactory.tableManager();
|
||||
Table table = tableManager.createTable(managerFactory.gamesRoomManager().getMainRoomId(), matchOptions);
|
||||
table.setTournamentSubTable(true);
|
||||
table.setTournament(tournament);
|
||||
table.setState(TableState.WAITING);
|
||||
|
@ -261,8 +259,8 @@ public class TournamentController {
|
|||
|
||||
private void startMultiplayerMatch(MultiplayerRound round, MatchOptions matchOptions) {
|
||||
try {
|
||||
TableManager tableManager = TableManager.instance;
|
||||
Table table = tableManager.createTable(GamesRoomManager.instance.getMainRoomId(), matchOptions);
|
||||
TableManager tableManager = managerFactory.tableManager();
|
||||
Table table = tableManager.createTable(managerFactory.gamesRoomManager().getMainRoomId(), matchOptions);
|
||||
table.setTournamentSubTable(true);
|
||||
table.setTournament(tournament);
|
||||
table.setState(TableState.WAITING);
|
||||
|
@ -287,16 +285,16 @@ public class TournamentController {
|
|||
}
|
||||
|
||||
private void startDraft(Draft draft) {
|
||||
TableManager.instance.startDraft(tableId, draft);
|
||||
managerFactory.tableManager().startDraft(tableId, draft);
|
||||
}
|
||||
|
||||
private void construct() {
|
||||
TableManager.instance.construct(tableId);
|
||||
managerFactory.tableManager().construct(tableId);
|
||||
}
|
||||
|
||||
private void initTournament() {
|
||||
if (TableManager.instance.getTable(tableId).getState() != TableState.DUELING) {
|
||||
TableManager.instance.initTournament(tableId);
|
||||
if (managerFactory.tableManager().getTable(tableId).getState() != TableState.DUELING) {
|
||||
managerFactory.tableManager().initTournament(tableId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,7 +303,7 @@ public class TournamentController {
|
|||
TournamentSession tournamentSession = tournamentSessions.get(playerId);
|
||||
tournamentSession.construct(timeout);
|
||||
getPlayerUserId(playerId).ifPresent(userId -> {
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
user.addConstructing(playerId, tournamentSession);
|
||||
TournamentPlayer player = tournament.getPlayer(playerId);
|
||||
player.setState(TournamentPlayerState.CONSTRUCTING);
|
||||
|
@ -319,7 +317,7 @@ public class TournamentController {
|
|||
TournamentPlayer player = tournament.getPlayer(playerId);
|
||||
if (player != null && !player.hasQuit()) {
|
||||
tournamentSessions.get(playerId).submitDeck(deck);
|
||||
ChatManager.instance.broadcast(chatId, "", player.getPlayer().getLogName() + " has submitted their tournament deck", MessageColor.BLACK, true, null, MessageType.STATUS, SoundToPlay.PlayerSubmittedDeck);
|
||||
managerFactory.chatManager().broadcast(chatId, "", player.getPlayer().getLogName() + " has submitted their tournament deck", MessageColor.BLACK, true, null, MessageType.STATUS, SoundToPlay.PlayerSubmittedDeck);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +336,7 @@ public class TournamentController {
|
|||
tournament.autoSubmit(userPlayerMap.get(userId), tournamentPlayer.generateDeck());
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
UserManager.instance.getUser(userId).ifPresent(user
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user
|
||||
-> sb.append(user.getName()));
|
||||
|
||||
sb.append(" - no deck found for auto submit");
|
||||
|
@ -380,16 +378,16 @@ public class TournamentController {
|
|||
if (tournament.isDoneConstructing()) {
|
||||
info = new StringBuilder("during round ").append(tournament.getRounds().size()).toString();
|
||||
// quit active matches of that tournament
|
||||
TableManager.instance.userQuitTournamentSubTables(tournament.getId(), userId);
|
||||
managerFactory.tableManager().userQuitTournamentSubTables(tournament.getId(), userId);
|
||||
status = TourneyQuitStatus.DURING_ROUND;
|
||||
} else if (tournamentPlayer.getState() == TournamentPlayerState.DRAFTING) {
|
||||
info = "during Draft phase";
|
||||
if (!checkToReplaceDraftPlayerByAi(userId, tournamentPlayer)) {
|
||||
this.abortDraftTournament();
|
||||
} else {
|
||||
DraftManager.instance.getController(tableId).ifPresent(draftController -> {
|
||||
managerFactory.draftManager().getController(tableId).ifPresent(draftController -> {
|
||||
draftController.getDraftSession(playerId).ifPresent(draftSession
|
||||
-> DraftManager.instance.kill(draftSession.getDraftId(), userId));
|
||||
-> managerFactory.draftManager().kill(draftSession.getDraftId(), userId));
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -404,7 +402,7 @@ public class TournamentController {
|
|||
tournamentPlayer.setQuit(info, status);
|
||||
tournament.quit(playerId);
|
||||
tournamentSession.quit();
|
||||
ChatManager.instance.broadcast(chatId, "", tournamentPlayer.getPlayer().getLogName() + " has quit the tournament", MessageColor.BLACK, true, null, MessageType.STATUS, SoundToPlay.PlayerQuitTournament);
|
||||
managerFactory.chatManager().broadcast(chatId, "", tournamentPlayer.getPlayer().getLogName() + " has quit the tournament", MessageColor.BLACK, true, null, MessageType.STATUS, SoundToPlay.PlayerQuitTournament);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,8 +415,8 @@ public class TournamentController {
|
|||
}
|
||||
// replace player that quits with draft bot
|
||||
if (humans > 1) {
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
TableManager.instance.getController(tableId).ifPresent(tableController -> {
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
managerFactory.tableManager().getController(tableId).ifPresent(tableController -> {
|
||||
|
||||
String replacePlayerName = "Draftbot";
|
||||
if (user.isPresent()) {
|
||||
|
@ -430,7 +428,7 @@ public class TournamentController {
|
|||
user.get().removeTable(leavingPlayer.getPlayer().getId());
|
||||
user.get().removeTournament(leavingPlayer.getPlayer().getId());
|
||||
}
|
||||
ChatManager.instance.broadcast(chatId, "", leavingPlayer.getPlayer().getLogName() + " was replaced by draftbot", MessageColor.BLACK, true, null, MessageType.STATUS, null);
|
||||
managerFactory.chatManager().broadcast(chatId, "", leavingPlayer.getPlayer().getLogName() + " was replaced by draftbot", MessageColor.BLACK, true, null, MessageType.STATUS, null);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -447,7 +445,7 @@ public class TournamentController {
|
|||
|
||||
private void abortDraftTournament() {
|
||||
tournament.setAbort(true);
|
||||
DraftManager.instance.getController(tableId).ifPresent(DraftController::abortDraft);
|
||||
managerFactory.draftManager().getController(tableId).ifPresent(DraftController::abortDraft);
|
||||
}
|
||||
|
||||
public boolean isAbort() {
|
||||
|
@ -472,7 +470,7 @@ public class TournamentController {
|
|||
}
|
||||
|
||||
public void cleanUpOnRemoveTournament() {
|
||||
ChatManager.instance.destroyChatSession(chatId);
|
||||
managerFactory.chatManager().destroyChatSession(chatId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -490,7 +488,7 @@ public class TournamentController {
|
|||
if (tournamentPlayer != null) {
|
||||
if (!tournamentPlayer.hasQuit()) {
|
||||
if (tournamentPlayer.getPlayer().isHuman()) {
|
||||
Optional<User> user = UserManager.instance.getUser(entry.getKey());
|
||||
Optional<User> user = managerFactory.userManager().getUser(entry.getKey());
|
||||
if (!user.isPresent()) {
|
||||
logger.debug("Tournament user is missing but player active -> start quit - tournamentId: " + tournament.getId() + " state: " + tableState.toString());
|
||||
// active tournament player but the user is no longer online
|
||||
|
|
|
@ -1,57 +1,71 @@
|
|||
|
||||
package mage.server.tournament;
|
||||
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.game.tournament.Tournament;
|
||||
import mage.server.managers.TournamentManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.view.TournamentView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.game.tournament.Tournament;
|
||||
import mage.view.TournamentView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum TournamentManager {
|
||||
instance;
|
||||
public class TournamentManagerImpl implements TournamentManager {
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
private final ConcurrentMap<UUID, TournamentController> controllers = new ConcurrentHashMap<>();
|
||||
|
||||
public TournamentManagerImpl(ManagerFactory managerFactory) {
|
||||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TournamentController> getTournamentController(UUID tournamentId) {
|
||||
return Optional.ofNullable(controllers.get(tournamentId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTournamentSession(Tournament tournament, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId) {
|
||||
TournamentController tournamentController = new TournamentController(tournament, userPlayerMap, tableId);
|
||||
TournamentController tournamentController = new TournamentController(managerFactory, tournament, userPlayerMap, tableId);
|
||||
controllers.put(tournament.getId(), tournamentController);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void joinTournament(UUID tournamentId, UUID userId) {
|
||||
controllers.get(tournamentId).join(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void quit(UUID tournamentId, UUID userId) {
|
||||
TournamentController tournamentController = controllers.get(tournamentId);
|
||||
if (tournamentController != null) {
|
||||
tournamentController.quit(userId);
|
||||
} else {
|
||||
Logger.getLogger(TournamentManager.class).error("Tournament controller missing tournamentid: " + tournamentId + " userId: " + userId);
|
||||
Logger.getLogger(TournamentManagerImpl.class).error("Tournament controller missing tournamentid: " + tournamentId + " userId: " + userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void timeout(UUID tournamentId, UUID userId) {
|
||||
controllers.get(tournamentId).timeout(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitDeck(UUID tournamentId, UUID playerId, Deck deck) {
|
||||
controllers.get(tournamentId).submitDeck(playerId, deck);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateDeck(UUID tournamentId, UUID playerId, Deck deck) {
|
||||
return controllers.get(tournamentId).updateDeck(playerId, deck);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TournamentView getTournamentView(UUID tournamentId) {
|
||||
TournamentController tournamentController = controllers.get(tournamentId);
|
||||
if (tournamentController != null) {
|
||||
|
@ -60,6 +74,7 @@ public enum TournamentManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<UUID> getChatId(UUID tournamentId) {
|
||||
if (controllers.containsKey(tournamentId)) {
|
||||
return Optional.of(controllers.get(tournamentId).getChatId());
|
||||
|
@ -67,6 +82,7 @@ public enum TournamentManager {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTournament(UUID tournamentId) {
|
||||
TournamentController tournamentController = controllers.get(tournamentId);
|
||||
if (tournamentController != null) {
|
|
@ -1,20 +1,19 @@
|
|||
|
||||
package mage.server.tournament;
|
||||
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.game.tournament.Tournament;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.interfaces.callback.ClientCallbackMethod;
|
||||
import mage.server.User;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
import mage.view.TournamentView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.game.tournament.Tournament;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.interfaces.callback.ClientCallbackMethod;
|
||||
import mage.server.User;
|
||||
import mage.server.UserManager;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
import mage.view.TournamentView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -23,6 +22,7 @@ public class TournamentSession {
|
|||
|
||||
protected static final Logger logger = Logger.getLogger(TournamentSession.class);
|
||||
|
||||
private final ManagerFactory managerFactory;
|
||||
protected final UUID userId;
|
||||
protected final UUID playerId;
|
||||
protected final UUID tableId;
|
||||
|
@ -30,9 +30,11 @@ public class TournamentSession {
|
|||
protected boolean killed = false;
|
||||
|
||||
private ScheduledFuture<?> futureTimeout;
|
||||
protected static final ScheduledExecutorService timeoutExecutor = ThreadExecutor.instance.getTimeoutExecutor();
|
||||
protected final ScheduledExecutorService timeoutExecutor;
|
||||
|
||||
public TournamentSession(Tournament tournament, UUID userId, UUID tableId, UUID playerId) {
|
||||
public TournamentSession(ManagerFactory managerFactory, Tournament tournament, UUID userId, UUID tableId, UUID playerId) {
|
||||
this.managerFactory = managerFactory;
|
||||
this.timeoutExecutor = managerFactory.threadExecutor().getTimeoutExecutor();
|
||||
this.userId = userId;
|
||||
this.tournament = tournament;
|
||||
this.playerId = playerId;
|
||||
|
@ -41,7 +43,7 @@ public class TournamentSession {
|
|||
|
||||
public boolean init() {
|
||||
if (!killed) {
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
if (user.isPresent()) {
|
||||
user.get().fireCallback(new ClientCallback(ClientCallbackMethod.TOURNAMENT_INIT, tournament.getId(), getTournamentView()));
|
||||
return true;
|
||||
|
@ -52,7 +54,7 @@ public class TournamentSession {
|
|||
|
||||
public void update() {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user
|
||||
-> user.fireCallback(new ClientCallback(ClientCallbackMethod.TOURNAMENT_UPDATE, tournament.getId(), getTournamentView())));
|
||||
|
||||
}
|
||||
|
@ -60,7 +62,7 @@ public class TournamentSession {
|
|||
|
||||
public void gameOver(final String message) {
|
||||
if (!killed) {
|
||||
UserManager.instance.getUser(userId).ifPresent(user
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user
|
||||
-> user.fireCallback(new ClientCallback(ClientCallbackMethod.TOURNAMENT_OVER, tournament.getId(), message)));
|
||||
|
||||
}
|
||||
|
@ -69,7 +71,7 @@ public class TournamentSession {
|
|||
public void construct(int timeout) {
|
||||
if (!killed) {
|
||||
setupTimeout(timeout);
|
||||
UserManager.instance.getUser(userId).ifPresent(user -> {
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
int remaining = (int) futureTimeout.getDelay(TimeUnit.SECONDS);
|
||||
user.ccConstruct(tournament.getPlayer(playerId).getDeck(), tableId, remaining);
|
||||
});
|
||||
|
@ -102,7 +104,7 @@ public class TournamentSession {
|
|||
futureTimeout = timeoutExecutor.schedule(
|
||||
() -> {
|
||||
try {
|
||||
TournamentManager.instance.timeout(tournament.getId(), userId);
|
||||
managerFactory.tournamentManager().timeout(tournament.getId(), userId);
|
||||
} catch (Exception e) {
|
||||
logger.fatal("TournamentSession error - userId " + userId + " tId " + tournament.getId(), e);
|
||||
}
|
||||
|
@ -144,7 +146,7 @@ public class TournamentSession {
|
|||
}
|
||||
|
||||
private void removeTournamentForUser() {
|
||||
Optional<User> user = UserManager.instance.getUser(userId);
|
||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||
if (user.isPresent()) {
|
||||
user.get().removeTable(playerId);
|
||||
user.get().removeTournament(playerId);
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package mage.server.util;
|
||||
|
||||
import mage.server.util.config.Config;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import java.io.File;
|
||||
|
||||
public class ConfigFactory {
|
||||
|
||||
public static Config loadFromFile(final String filePath) {
|
||||
try {
|
||||
final JAXBContext jaxbContext = JAXBContext.newInstance("mage.server.util.config");
|
||||
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
|
||||
return (Config) unmarshaller.unmarshal(new File(filePath));
|
||||
} catch (Exception e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +1,18 @@
|
|||
|
||||
package mage.server.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import mage.server.managers.ConfigSettings;
|
||||
import mage.server.util.config.Config;
|
||||
import mage.server.util.config.GamePlugin;
|
||||
import mage.server.util.config.Plugin;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum ConfigSettings {
|
||||
instance;
|
||||
private final Logger logger = Logger.getLogger(ConfigSettings.class);
|
||||
import java.util.List;
|
||||
|
||||
private Config config;
|
||||
public class ConfigWrapper implements ConfigSettings {
|
||||
|
||||
ConfigSettings() {
|
||||
try {
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance("mage.server.util.config");
|
||||
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
|
||||
config = (Config) unmarshaller.unmarshal(new File("config/config.xml"));
|
||||
} catch (JAXBException ex) {
|
||||
logger.fatal("ConfigSettings error", ex);
|
||||
}
|
||||
private final Config config;
|
||||
|
||||
public ConfigWrapper(final Config config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public String getServerAddress() {
|
|
@ -0,0 +1,7 @@
|
|||
package mage.server.util;
|
||||
|
||||
public class ConfigurationException extends RuntimeException {
|
||||
public ConfigurationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
|
@ -1,24 +1,18 @@
|
|||
|
||||
package mage.server.util;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import mage.server.managers.ConfigSettings;
|
||||
import mage.server.managers.ThreadExecutor;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public enum ThreadExecutor {
|
||||
instance;
|
||||
private static final ExecutorService callExecutor = Executors.newCachedThreadPool();
|
||||
private static final ExecutorService userExecutor = Executors.newCachedThreadPool();
|
||||
private static final ExecutorService gameExecutor = Executors.newFixedThreadPool(ConfigSettings.instance.getMaxGameThreads());
|
||||
private static final ScheduledExecutorService timeoutExecutor = Executors.newScheduledThreadPool(4);
|
||||
private static final ScheduledExecutorService timeoutIdleExecutor = Executors.newScheduledThreadPool(4);
|
||||
public class ThreadExecutorImpl implements ThreadExecutor {
|
||||
private final ExecutorService callExecutor;
|
||||
private final ExecutorService gameExecutor;
|
||||
private final ScheduledExecutorService timeoutExecutor;
|
||||
private final ScheduledExecutorService timeoutIdleExecutor;
|
||||
|
||||
/**
|
||||
* noxx: what the settings below do is setting the ability to keep OS
|
||||
|
@ -26,17 +20,20 @@ instance;
|
|||
* within this time period, the thread may be discarded. But anyway if new
|
||||
* game is created later, new OS/java thread will be created for it taking
|
||||
* MaxGameThreads limit into account.
|
||||
*
|
||||
* <p>
|
||||
* This all is done for performance reasons as creating new OS threads is
|
||||
* resource consuming process.
|
||||
*/
|
||||
static {
|
||||
|
||||
public ThreadExecutorImpl(ConfigSettings config) {
|
||||
callExecutor = Executors.newCachedThreadPool();
|
||||
gameExecutor = Executors.newFixedThreadPool(config.getMaxGameThreads());
|
||||
timeoutExecutor = Executors.newScheduledThreadPool(4);
|
||||
timeoutIdleExecutor = Executors.newScheduledThreadPool(4);
|
||||
|
||||
((ThreadPoolExecutor) callExecutor).setKeepAliveTime(60, TimeUnit.SECONDS);
|
||||
((ThreadPoolExecutor) callExecutor).allowCoreThreadTimeOut(true);
|
||||
((ThreadPoolExecutor) callExecutor).setThreadFactory(new XMageThreadFactory("CALL"));
|
||||
((ThreadPoolExecutor) userExecutor).setKeepAliveTime(60, TimeUnit.SECONDS);
|
||||
((ThreadPoolExecutor) userExecutor).allowCoreThreadTimeOut(true);
|
||||
((ThreadPoolExecutor) userExecutor).setThreadFactory(new XMageThreadFactory("USER"));
|
||||
((ThreadPoolExecutor) gameExecutor).setKeepAliveTime(60, TimeUnit.SECONDS);
|
||||
((ThreadPoolExecutor) gameExecutor).allowCoreThreadTimeOut(true);
|
||||
((ThreadPoolExecutor) gameExecutor).setThreadFactory(new XMageThreadFactory("GAME"));
|
||||
|
@ -49,6 +46,7 @@ instance;
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getActiveThreads(ExecutorService executerService) {
|
||||
if (executerService instanceof ThreadPoolExecutor) {
|
||||
return ((ThreadPoolExecutor) executerService).getActiveCount();
|
||||
|
@ -56,18 +54,22 @@ instance;
|
|||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutorService getCallExecutor() {
|
||||
return callExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutorService getGameExecutor() {
|
||||
return gameExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledExecutorService getTimeoutExecutor() {
|
||||
return timeoutExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledExecutorService getTimeoutIdleExecutor() {
|
||||
return timeoutIdleExecutor;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package mage.server.util;
|
||||
|
||||
import mage.server.util.config.Config;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
public class ConfigFactoryTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("should unmarshal configuration from file")
|
||||
void loadConfig() {
|
||||
final Config config = ConfigFactory.loadFromFile("config/config.xml");
|
||||
|
||||
assertThat(config.getServer().getServerName()).isEqualTo("mage-server");
|
||||
assertThat(config.getServer().getPort()).isEqualTo(17171);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail if config is malformed")
|
||||
void failOnMalformed() {
|
||||
assertThatExceptionOfType(ConfigurationException.class)
|
||||
.isThrownBy(() -> ConfigFactory.loadFromFile(Paths.get("src", "test", "resources", "config_error.xml").toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("should fail if file does not exist")
|
||||
void failOnNotFound() {
|
||||
assertThatExceptionOfType(ConfigurationException.class)
|
||||
.isThrownBy(() -> ConfigFactory.loadFromFile("does not exist"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
package mage.server.util;
|
||||
|
||||
import mage.server.util.config.*;
|
||||
import mage.utils.FluentBuilder;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.DynamicTest;
|
||||
import org.junit.jupiter.api.TestFactory;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class ConfigWrapperTest {
|
||||
|
||||
static class ConfigBuilder extends FluentBuilder<Config, ConfigBuilder> {
|
||||
|
||||
public String serverAddress;
|
||||
public String serverName;
|
||||
public int port;
|
||||
public int secondaryBindPort;
|
||||
public int leasePeriod;
|
||||
public int socketWriteTimeout;
|
||||
public int maxPoolSize;
|
||||
public int numAcceptThreads;
|
||||
public int backlogSize;
|
||||
public int maxGameThreads;
|
||||
public int maxSecondsIdle;
|
||||
public int minUsernameLength;
|
||||
public int maxUsernameLength;
|
||||
public String invalidUsernamePattern;
|
||||
public int minPasswordLength;
|
||||
public int maxPasswordLength;
|
||||
public String maxAiOpponents;
|
||||
public boolean saveGameActivated;
|
||||
public boolean authenticationActivated;
|
||||
public String googleAccount;
|
||||
public String mailgunApiKey;
|
||||
public String mailgunDomain;
|
||||
public String mailSmtpHost;
|
||||
public String mailSmtpPort;
|
||||
public String mailUser;
|
||||
public String mailPassword;
|
||||
public String mailFromAddress;
|
||||
public List<Plugin> playerTypes = Collections.emptyList();
|
||||
public List<GamePlugin> gameTypes = Collections.emptyList();
|
||||
public List<GamePlugin> tournamentTypes = Collections.emptyList();
|
||||
public List<Plugin> draftCubes = Collections.emptyList();
|
||||
public List<Plugin> deckTypes = Collections.emptyList();
|
||||
|
||||
private ConfigBuilder() {
|
||||
super(ConfigBuilder::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config makeValue() {
|
||||
final Config result = new Config();
|
||||
result.setServer(makeServer());
|
||||
result.setPlayerTypes(makePlayerTypes());
|
||||
result.setGameTypes(makeGameTypes());
|
||||
result.setTournamentTypes(makeTournamentTypes());
|
||||
result.setDraftCubes(makeDraftCubes());
|
||||
result.setDeckTypes(makeDeckTypes());
|
||||
return result;
|
||||
}
|
||||
|
||||
private Server makeServer() {
|
||||
final Server server = new Server();
|
||||
server.setServerAddress(serverAddress);
|
||||
server.setServerName(serverName);
|
||||
server.setPort(BigInteger.valueOf(port));
|
||||
server.setSecondaryBindPort(bi(secondaryBindPort));
|
||||
server.setLeasePeriod(bi(leasePeriod));
|
||||
server.setSocketWriteTimeout(bi(socketWriteTimeout));
|
||||
server.setMaxPoolSize(bi(maxPoolSize));
|
||||
server.setNumAcceptThreads(bi(numAcceptThreads));
|
||||
server.setBacklogSize(bi(backlogSize));
|
||||
server.setMaxGameThreads(bi(maxGameThreads));
|
||||
server.setMaxSecondsIdle(bi(maxSecondsIdle));
|
||||
server.setMinUserNameLength(bi(minUsernameLength));
|
||||
server.setMaxUserNameLength(bi(maxUsernameLength));
|
||||
server.setInvalidUserNamePattern(invalidUsernamePattern);
|
||||
server.setMinPasswordLength(bi(minPasswordLength));
|
||||
server.setMaxPasswordLength(bi(maxPasswordLength));
|
||||
server.setMaxAiOpponents(maxAiOpponents);
|
||||
server.setSaveGameActivated(saveGameActivated);
|
||||
server.setAuthenticationActivated(authenticationActivated);
|
||||
server.setGoogleAccount(googleAccount);
|
||||
server.setMailgunApiKey(mailgunApiKey);
|
||||
server.setMailgunDomain(mailgunDomain);
|
||||
server.setMailSmtpHost(mailSmtpHost);
|
||||
server.setMailSmtpPort(mailSmtpPort);
|
||||
server.setMailUser(mailUser);
|
||||
server.setMailPassword(mailPassword);
|
||||
server.setMailFromAddress(mailFromAddress);
|
||||
return server;
|
||||
}
|
||||
|
||||
private PlayerTypes makePlayerTypes() {
|
||||
final PlayerTypes playerTypes = new PlayerTypes();
|
||||
this.playerTypes.forEach(p -> playerTypes.getPlayerType().add(p));
|
||||
return playerTypes;
|
||||
}
|
||||
|
||||
private GameTypes makeGameTypes() {
|
||||
final GameTypes gameTypes = new GameTypes();
|
||||
this.gameTypes.forEach(g -> gameTypes.getGameType().add(g));
|
||||
return gameTypes;
|
||||
}
|
||||
|
||||
private TournamentTypes makeTournamentTypes() {
|
||||
final TournamentTypes tournamentTypes = new TournamentTypes();
|
||||
this.tournamentTypes.forEach(t -> tournamentTypes.getTournamentType().add(t));
|
||||
return tournamentTypes;
|
||||
}
|
||||
|
||||
private DraftCubes makeDraftCubes() {
|
||||
final DraftCubes draftCubes = new DraftCubes();
|
||||
this.draftCubes.forEach(d -> draftCubes.getDraftCube().add(d));
|
||||
return draftCubes;
|
||||
}
|
||||
|
||||
private DeckTypes makeDeckTypes() {
|
||||
final DeckTypes deckTypes = new DeckTypes();
|
||||
this.deckTypes.forEach(d -> deckTypes.getDeckType().add(d));
|
||||
return deckTypes;
|
||||
}
|
||||
|
||||
private BigInteger bi(int value) {
|
||||
return BigInteger.valueOf(value);
|
||||
}
|
||||
}
|
||||
|
||||
private ConfigBuilder baseConfigBuilder() {
|
||||
return new ConfigBuilder();
|
||||
}
|
||||
|
||||
private final String expectedString = RandomStringUtils.randomAlphanumeric(15);
|
||||
private final int expectedPositiveInt = RandomUtils.nextInt(0, Integer.MAX_VALUE);
|
||||
|
||||
|
||||
@TestFactory
|
||||
@DisplayName("should return from server")
|
||||
Stream<DynamicTest> assignmentFromServer() {
|
||||
return Stream.of(
|
||||
testString("server address", c -> c.serverAddress = expectedString, ConfigWrapper::getServerAddress),
|
||||
testString("server name", c -> c.serverName = expectedString, ConfigWrapper::getServerName),
|
||||
testInt("port", c -> c.port = expectedPositiveInt, ConfigWrapper::getPort),
|
||||
testInt("secondary bind port", c -> c.secondaryBindPort = expectedPositiveInt, ConfigWrapper::getSecondaryBindPort),
|
||||
testInt("lease period", c -> c.leasePeriod = expectedPositiveInt, ConfigWrapper::getLeasePeriod),
|
||||
testInt("socket write timeout", c -> c.socketWriteTimeout = expectedPositiveInt, ConfigWrapper::getSocketWriteTimeout),
|
||||
testInt("max pool size", c -> c.maxPoolSize = expectedPositiveInt, ConfigWrapper::getMaxPoolSize),
|
||||
testInt("number of accept threads", c -> c.numAcceptThreads = expectedPositiveInt, ConfigWrapper::getNumAcceptThreads),
|
||||
testInt("backlog size", c -> c.backlogSize = expectedPositiveInt, ConfigWrapper::getBacklogSize),
|
||||
testInt("max game threads", c -> c.maxGameThreads = expectedPositiveInt, ConfigWrapper::getMaxGameThreads),
|
||||
testInt("max seconds idle", c -> c.maxSecondsIdle = expectedPositiveInt, ConfigWrapper::getMaxSecondsIdle),
|
||||
testInt("min username length", c -> c.minUsernameLength = expectedPositiveInt, ConfigWrapper::getMinUserNameLength),
|
||||
testInt("max username length", c -> c.maxUsernameLength = expectedPositiveInt, ConfigWrapper::getMaxUserNameLength),
|
||||
testString("invalid username pattern", c -> c.invalidUsernamePattern = expectedString, ConfigWrapper::getInvalidUserNamePattern),
|
||||
testInt("min password length", c -> c.minPasswordLength = expectedPositiveInt, ConfigWrapper::getMinPasswordLength),
|
||||
testInt("max password length", c -> c.maxPasswordLength = expectedPositiveInt, ConfigWrapper::getMaxPasswordLength),
|
||||
testString("max AI opponents", c -> c.maxAiOpponents = expectedString, ConfigWrapper::getMaxAiOpponents),
|
||||
testTrue("save game activated", c -> c.saveGameActivated = true, ConfigWrapper::isSaveGameActivated),
|
||||
testTrue("authentication activated", c -> c.authenticationActivated = true, ConfigWrapper::isAuthenticationActivated),
|
||||
testString("google account", c -> c.googleAccount = expectedString, ConfigWrapper::getGoogleAccount),
|
||||
testString("mailgun api key", c -> c.mailgunApiKey = expectedString, ConfigWrapper::getMailgunApiKey),
|
||||
testString("mailgun domain", c -> c.mailgunDomain = expectedString, ConfigWrapper::getMailgunDomain),
|
||||
testString("mail smtp host", c -> c.mailSmtpHost = expectedString, ConfigWrapper::getMailSmtpHost),
|
||||
testString("mail smtp port", c -> c.mailSmtpPort = expectedString, ConfigWrapper::getMailSmtpPort),
|
||||
testString("mail from address", c -> c.mailFromAddress = expectedString, ConfigWrapper::getMailFromAddress),
|
||||
testString("mail user", c -> c.mailUser = expectedString, ConfigWrapper::getMailUser),
|
||||
testString("mail password", c -> c.mailPassword = expectedString, ConfigWrapper::getMailPassword)
|
||||
);
|
||||
}
|
||||
|
||||
private DynamicTest testString(String description, Consumer<ConfigBuilder> builderSetter, Function<ConfigWrapper, Object> valueExtractor) {
|
||||
return testTemplate(description, builderSetter, valueExtractor, expectedString);
|
||||
}
|
||||
|
||||
private DynamicTest testTemplate(String description, Consumer<ConfigBuilder> builderSetter, Function<ConfigWrapper, Object> valueExtractor, Object expectedValue) {
|
||||
return DynamicTest.dynamicTest(description, () -> assertThat(valueExtractor.apply(makeTestee(baseConfigBuilder().with(builderSetter)))).isEqualTo(expectedValue));
|
||||
}
|
||||
|
||||
private ConfigWrapper makeTestee(ConfigBuilder builder) {
|
||||
return new ConfigWrapper(builder.build());
|
||||
}
|
||||
|
||||
private DynamicTest testInt(String description, Consumer<ConfigBuilder> builderSetter, Function<ConfigWrapper, Object> valueExtractor) {
|
||||
return testTemplate(description, builderSetter, valueExtractor, expectedPositiveInt);
|
||||
}
|
||||
|
||||
private DynamicTest testTrue(String description, Consumer<ConfigBuilder> builderSetter, Function<ConfigWrapper, Object> valueExtractor) {
|
||||
return testTemplate(description, builderSetter, valueExtractor, true);
|
||||
}
|
||||
|
||||
|
||||
private final Comparator<Plugin> pluginComparator = (p1, p2) -> {
|
||||
if (Objects.equals(p1.getName(), p2.getName()) &&
|
||||
Objects.equals(p1.getJar(), p2.getJar()) &&
|
||||
Objects.equals(p1.getClassName(), p2.getClassName())) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
private final Comparator<GamePlugin> gamePluginComparator = (p1, p2) -> {
|
||||
if (Objects.equals(p1.getName(), p2.getName()) &&
|
||||
Objects.equals(p1.getJar(), p2.getJar()) &&
|
||||
Objects.equals(p1.getClassName(), p2.getClassName()) &&
|
||||
Objects.equals(p1.getTypeName(), p2.getTypeName())) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
private final List<Plugin> randomPlugins = IntStream.range(0, RandomUtils.nextInt(1, 10))
|
||||
.mapToObj(i -> makePlugin(
|
||||
RandomStringUtils.randomAlphanumeric(15),
|
||||
RandomStringUtils.randomAlphanumeric(16),
|
||||
RandomStringUtils.randomAlphanumeric(17))
|
||||
).collect(Collectors.toList());
|
||||
private final List<GamePlugin> randomGamePlugins = IntStream.range(0, RandomUtils.nextInt(1, 10))
|
||||
.mapToObj(i -> makeGamePlugin(
|
||||
RandomStringUtils.randomAlphanumeric(15),
|
||||
RandomStringUtils.randomAlphanumeric(16),
|
||||
RandomStringUtils.randomAlphanumeric(17),
|
||||
RandomStringUtils.randomAlphanumeric(18))
|
||||
).collect(Collectors.toList());
|
||||
|
||||
private Plugin makePlugin(String name, String jar, String className) {
|
||||
final Plugin plugin = new Plugin();
|
||||
plugin.setName(name);
|
||||
plugin.setJar(jar);
|
||||
plugin.setClassName(className);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
private GamePlugin makeGamePlugin(String name, String jar, String className, String typeName) {
|
||||
final GamePlugin plugin = new GamePlugin();
|
||||
plugin.setName(name);
|
||||
plugin.setJar(jar);
|
||||
plugin.setClassName(className);
|
||||
plugin.setTypeName(typeName);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
@DisplayName("should extract")
|
||||
Stream<DynamicTest> pluginsExtraction() {
|
||||
return Stream.of(
|
||||
pluginTest("playerTypes from playerTypes", c -> c.playerTypes = randomPlugins, ConfigWrapper::getPlayerTypes),
|
||||
gamePluginTest("gameTypes from gameTypes", c -> c.gameTypes = randomGamePlugins, ConfigWrapper::getGameTypes),
|
||||
gamePluginTest("tournamentTypes from tournamentTypes", c -> c.tournamentTypes = randomGamePlugins, ConfigWrapper::getTournamentTypes),
|
||||
pluginTest("draftCubes from draftCubes", c -> c.draftCubes = randomPlugins, ConfigWrapper::getDraftCubes),
|
||||
pluginTest("deckTypes from deckTypes", c -> c.deckTypes = randomPlugins, ConfigWrapper::getDeckTypes)
|
||||
);
|
||||
}
|
||||
|
||||
private DynamicTest pluginTest(String description,
|
||||
Consumer<ConfigBuilder> builderSetter,
|
||||
Function<ConfigWrapper, List<Plugin>> listExtractor) {
|
||||
return testTemplateForLists(description, builderSetter, listExtractor, randomPlugins, pluginComparator);
|
||||
}
|
||||
|
||||
private DynamicTest gamePluginTest(String description,
|
||||
Consumer<ConfigBuilder> builderSetter,
|
||||
Function<ConfigWrapper, List<GamePlugin>> listExtractor) {
|
||||
return testTemplateForLists(description, builderSetter, listExtractor, randomGamePlugins, gamePluginComparator);
|
||||
}
|
||||
|
||||
private <T> DynamicTest testTemplateForLists(String description,
|
||||
Consumer<ConfigBuilder> builderSetter,
|
||||
Function<ConfigWrapper, List<T>> listExtractor,
|
||||
List<T> expectedValue,
|
||||
Comparator<T> comparator) {
|
||||
return DynamicTest.dynamicTest(description, () ->
|
||||
assertThat(listExtractor.apply(makeTestee(baseConfigBuilder().with(builderSetter))))
|
||||
.usingElementComparator(comparator)
|
||||
.containsExactlyElementsOf(expectedValue)
|
||||
);
|
||||
}
|
||||
}
|
173
Mage.Server/src/test/resources/config_error.xml
Normal file
173
Mage.Server/src/test/resources/config_error.xml
Normal file
|
@ -0,0 +1,173 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- Configuration file with integers set as strings to cause unmarshalling errors -->
|
||||
<config>
|
||||
<server serverAddress="0.0.0.0"
|
||||
serverName="mage-server"
|
||||
port="NOT AN INTEGER"
|
||||
secondaryBindPort="NOT AN INTEGER"
|
||||
backlogSize="NOT AN INTEGER"
|
||||
numAcceptThreads="NOT AN INTEGER"
|
||||
maxPoolSize="NOT AN INTEGER"
|
||||
leasePeriod="NOT AN INTEGER"
|
||||
socketWriteTimeout="NOT AN INTEGER"
|
||||
maxGameThreads="NOT AN INTEGER"
|
||||
maxSecondsIdle="NOT AN INTEGER"
|
||||
minUserNameLength="NOT AN INTEGER"
|
||||
maxUserNameLength="NOT AN INTEGER"
|
||||
invalidUserNamePattern="[^a-z0-9_]"
|
||||
minPasswordLength="NOT AN INTEGER"
|
||||
maxPasswordLength="NOT AN INTEGER"
|
||||
maxAiOpponents="NOT AN INTEGER"
|
||||
saveGameActivated="false"
|
||||
authenticationActivated="false"
|
||||
googleAccount=""
|
||||
mailgunApiKey=""
|
||||
mailgunDomain=""
|
||||
mailSmtpHost=""
|
||||
mailSmtpPort=""
|
||||
mailUser=""
|
||||
mailPassword=""
|
||||
mailFromAddress=""
|
||||
/>
|
||||
<playerTypes>
|
||||
<playerType name="Human" jar="mage-player-human.jar" className="mage.player.human.HumanPlayer"/>
|
||||
<!--<playerType name="Computer - minimax" jar="mage-player-aiminimax.jar" className="mage.player.ai.ComputerPlayer3"/>-->
|
||||
<playerType name="Computer - mad" jar="mage-player-ai-ma.jar" className="mage.player.ai.ComputerPlayer7"/>
|
||||
<playerType name="Computer - monte carlo" jar="mage-player-aimcts.jar" className="mage.player.ai.ComputerPlayerMCTS"/>
|
||||
<playerType name="Computer - draftbot" jar="mage-player-ai-draft-bot.jar" className="mage.player.ai.ComputerDraftPlayer"/>
|
||||
</playerTypes>
|
||||
<gameTypes>
|
||||
<gameType name="Two Player Duel" jar="mage-game-twoplayerduel.jar" className="mage.game.TwoPlayerMatch" typeName="mage.game.TwoPlayerDuelType"/>
|
||||
<gameType name="Free For All" jar="mage-game-freeforall.jar" className="mage.game.FreeForAllMatch" typeName="mage.game.FreeForAllType"/>
|
||||
<gameType name="Commander Two Player Duel" jar="mage-game-commanderduel.jar" className="mage.game.CommanderDuelMatch" typeName="mage.game.CommanderDuelType"/>
|
||||
<gameType name="Commander Free For All" jar="mage-game-commanderfreeforall.jar" className="mage.game.CommanderFreeForAllMatch" typeName="mage.game.CommanderFreeForAllType"/>
|
||||
<gameType name="Tiny Leaders Two Player Duel" jar="mage-game-tinyleadersduel.jar" className="mage.game.TinyLeadersDuelMatch" typeName="mage.game.TinyLeadersDuelType"/>
|
||||
<gameType name="Canadian Highlander Two Player Duel" jar="mage-game-canadianhighlanderduel.jar" className="mage.game.CanadianHighlanderDuelMatch" typeName="mage.game.CanadianHighlanderDuelType"/>
|
||||
<gameType name="Penny Dreadful Commander Free For All" jar="mage-game-pennydreadfulcommanderfreeforall.jar" className="mage.game.PennyDreadfulCommanderFreeForAllMatch" typeName="mage.game.PennyDreadfulCommanderFreeForAllType"/>
|
||||
<gameType name="Freeform Commander Two Player Duel" jar="mage-game-freeformcommanderduel.jar" className="mage.game.FreeformCommanderDuelMatch" typeName="mage.game.FreeformCommanderDuelType"/>
|
||||
<gameType name="Freeform Commander Free For All" jar="mage-game-freeformcommanderfreeforall.jar" className="mage.game.FreeformCommanderFreeForAllMatch" typeName="mage.game.FreeformCommanderFreeForAllType"/>
|
||||
<gameType name="Freeform Unlimited Commander" jar="mage-game-freeformunlimitedcommander.jar" className="mage.game.FreeformUnlimitedCommanderMatch" typeName="mage.game.FreeformUnlimitedCommanderType"/>
|
||||
<gameType name="Oathbreaker Two Player Duel" jar="mage-game-oathbreakerduel.jar" className="mage.game.OathbreakerDuelMatch" typeName="mage.game.OathbreakerDuelType"/>
|
||||
<gameType name="Oathbreaker Free For All" jar="mage-game-oathbreakerfreeforall.jar" className="mage.game.OathbreakerFreeForAllMatch" typeName="mage.game.OathbreakerFreeForAllType"/>
|
||||
<gameType name="Brawl Two Player Duel" jar="mage-game-brawlduel.jar" className="mage.game.BrawlDuelMatch" typeName="mage.game.BrawlDuelType"/>
|
||||
<gameType name="Brawl Free For All" jar="mage-game-brawlfreeforall.jar" className="mage.game.BrawlFreeForAllMatch" typeName="mage.game.BrawlFreeForAllType"/>
|
||||
<gameType name="Momir Basic Two Player Duel" jar="mage-game-momirduel.jar" className="mage.game.MomirDuelMatch" typeName="mage.game.MomirDuelType"/>
|
||||
<gameType name="Momir Basic Free For All" jar="mage-game-momir.jar" className="mage.game.MomirFreeForAllMatch" typeName="mage.game.MomirFreeForAllType"/>
|
||||
</gameTypes>
|
||||
<tournamentTypes>
|
||||
<tournamentType name="Constructed Elimination" jar="mage-tournament-constructed.jar" className="mage.tournament.ConstructedEliminationTournament" typeName="mage.tournament.ConstructedEliminationTournamentType"/>
|
||||
<tournamentType name="Constructed Swiss" jar="mage-tournament-constructed.jar" className="mage.tournament.ConstructedSwissTournament" typeName="mage.tournament.ConstructedSwissTournamentType"/>
|
||||
<tournamentType name="Booster Draft Elimination" jar="mage-tournament-booster-draft.jar" className="mage.tournament.BoosterDraftEliminationTournament" typeName="mage.tournament.BoosterDraftEliminationTournamentType"/>
|
||||
<tournamentType name="Booster Draft Elimination (Cube)" jar="mage-tournament-booster-draft.jar" className="mage.tournament.BoosterDraftEliminationTournament" typeName="mage.tournament.BoosterDraftEliminationCubeTournamentType"/>
|
||||
<tournamentType name="Booster Draft Elimination (Random)" jar="mage-tournament-booster-draft.jar" className="mage.tournament.RandomBoosterDraftEliminationTournament" typeName="mage.tournament.RandomBoosterDraftEliminationTournamentType"/>
|
||||
<tournamentType name="Booster Draft Elimination (Rich Man)" jar="mage-tournament-booster-draft.jar" className="mage.tournament.RichManDraftEliminationTournament" typeName="mage.tournament.RichManDraftEliminationTournamentType"/>
|
||||
<tournamentType name="Booster Draft Elimination (Rich Man Cube)" jar="mage-tournament-booster-draft.jar" className="mage.tournament.RichManCubeDraftEliminationTournament" typeName="mage.tournament.RichManCubeDraftEliminationTournamentType"/>
|
||||
<tournamentType name="Booster Draft Swiss" jar="mage-tournament-booster-draft.jar" className="mage.tournament.BoosterDraftSwissTournament" typeName="mage.tournament.BoosterDraftSwissTournamentType"/>
|
||||
<tournamentType name="Booster Draft Swiss (Cube)" jar="mage-tournament-booster-draft.jar" className="mage.tournament.BoosterDraftSwissTournament" typeName="mage.tournament.BoosterDraftSwissCubeTournamentType"/>
|
||||
<tournamentType name="Booster Draft Swiss (Random)" jar="mage-tournament-booster-draft.jar" className="mage.tournament.RandomBoosterDraftSwissTournament" typeName="mage.tournament.RandomBoosterDraftSwissTournamentType"/>
|
||||
<tournamentType name="Sealed Elimination" jar="mage-tournament-sealed.jar" className="mage.tournament.SealedEliminationTournament" typeName="mage.tournament.SealedEliminationTournamentType"/>
|
||||
<tournamentType name="Sealed Elimination (Cube)" jar="mage-tournament-sealed.jar" className="mage.tournament.SealedEliminationTournament" typeName="mage.tournament.SealedEliminationCubeTournamentType"/>
|
||||
<tournamentType name="Sealed Swiss" jar="mage-tournament-sealed.jar" className="mage.tournament.SealedSwissTournament" typeName="mage.tournament.SealedSwissTournamentType"/>
|
||||
<tournamentType name="Sealed Swiss (Cube)" jar="mage-tournament-sealed.jar" className="mage.tournament.SealedSwissTournament" typeName="mage.tournament.SealedSwissCubeTournamentType"/>
|
||||
<tournamentType name="Jumpstart Elimination" jar="mage-tournament-sealed.jar" className="mage.tournament.JumpstartEliminationTournament" typeName="mage.tournament.JumpstartEliminationTournamentType"/>
|
||||
<tournamentType name="Jumpstart Swiss" jar="mage-tournament-sealed.jar" className="mage.tournament.JumpstartSwissTournament" typeName="mage.tournament.JumpstartSwissTournamentType"/>
|
||||
</tournamentTypes>
|
||||
<draftCubes>
|
||||
<draftCube name="Adam Styborski's Pauper Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.AdamStyborskisPauperCube"/>
|
||||
<draftCube name="Ben's Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.BensCube"/>
|
||||
<draftCube name="Cube Tutor 360 Pauper" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.CubeTutor360Pauper"/>
|
||||
<draftCube name="Cube Tutor 720" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.CubeTutor720"/>
|
||||
<draftCube name="Eric Klug's Pro Tour Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.EricKlugsProTourCube"/>
|
||||
<draftCube name="Guillaume Matignon's Jenny's/Johnny's Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.GuillaumeMatignonsJennysJohnnysCube"/>
|
||||
<draftCube name="Jim Davis's Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.JimDavisCube"/>
|
||||
<draftCube name="Joseph Vasoli's Peasant Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.JosephVasolisPeasantCube"/>
|
||||
<draftCube name="Mono Blue Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MonoBlueCube"/>
|
||||
<draftCube name="Sam Black's No Search Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.SamBlacksCube"/>
|
||||
<draftCube name="Timothee Simonot's Twisted Color Pie Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.TimotheeSimonotsTwistedColorPieCube"/>
|
||||
<draftCube name="MTGA Cube 2020 April" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGACube2020April"/>
|
||||
<draftCube name="MTGO Cube March 2014" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOMarchCube2014"/>
|
||||
<draftCube name="MTGO Legacy Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCube"/>
|
||||
<draftCube name="MTGO Legacy Cube 2015 March" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
|
||||
<draftCube name="MTGO Legacy Cube 2015 September" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/>
|
||||
<draftCube name="MTGO Legacy Cube 2016 January" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/>
|
||||
<draftCube name="MTGO Legacy Cube 2016 September" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeSeptember2016"/>
|
||||
<draftCube name="MTGO Legacy Cube 2017 January" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeJanuary2017"/>
|
||||
<draftCube name="MTGO Legacy Cube 2017 April" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeApril2017"/>
|
||||
<draftCube name="MTGO Legacy Cube 2018 February" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCube2018February"/>
|
||||
<draftCube name="MTGO Legacy Cube 2019 July" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeJuly2019"/>
|
||||
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/>
|
||||
<draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCubeApril2016"/>
|
||||
<draftCube name="MTGO Modern Cube 2017" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.ModernCube2017"/>
|
||||
<draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2013"/>
|
||||
<draftCube name="MTGO Vintage Cube 2014" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2014"/>
|
||||
<draftCube name="MTGO Vintage Cube 2015" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2015"/>
|
||||
<draftCube name="MTGO Vintage Cube 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2016"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeJune2016"/>
|
||||
<draftCube name="MTGO Vintage Cube November 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeNovember2016"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2017" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeJune2017"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2017" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeDecember2017"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2018" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeJune2018"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2018" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeDecember2018"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2019" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeJune2019"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2019" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeDecember2019"/>
|
||||
<draftCube name="MTGO Vintage Cube April 2020" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeApril2020"/>
|
||||
<draftCube name="MTGO Vintage Cube July 2020" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeJuly2020"/>
|
||||
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.ScgConCube2018December"/>
|
||||
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
|
||||
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGCube"/>
|
||||
<draftCube name="Cube From Deck" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.CubeFromDeck"/>
|
||||
</draftCubes>
|
||||
<deckTypes>
|
||||
<deckType name="Constructed - Standard" jar="mage-deck-constructed.jar" className="mage.deck.Standard"/>
|
||||
<deckType name="Constructed - Extended" jar="mage-deck-constructed.jar" className="mage.deck.Extended"/>
|
||||
<deckType name="Constructed - Frontier" jar="mage-deck-constructed.jar" className="mage.deck.Frontier"/>
|
||||
<deckType name="Constructed - Pioneer" jar="mage-deck-constructed.jar" className="mage.deck.Pioneer"/>
|
||||
<deckType name="Constructed - Modern" jar="mage-deck-constructed.jar" className="mage.deck.Modern"/>
|
||||
<deckType name="Constructed - Modern - No Banned List" jar="mage-deck-constructed.jar" className="mage.deck.ModernNoBannedList"/>
|
||||
<deckType name="Constructed - Eternal" jar="mage-deck-constructed.jar" className="mage.deck.Eternal"/>
|
||||
<deckType name="Constructed - Legacy" jar="mage-deck-constructed.jar" className="mage.deck.Legacy"/>
|
||||
<deckType name="Constructed - Vintage" jar="mage-deck-constructed.jar" className="mage.deck.Vintage"/>
|
||||
<deckType name="Constructed - Pauper" jar="mage-deck-constructed.jar" className="mage.deck.Pauper"/>
|
||||
<deckType name="Constructed - Historic" jar="mage-deck-constructed.jar" className="mage.deck.Historic"/>
|
||||
<deckType name="Constructed - Historical Type 2" jar="mage-deck-constructed.jar" className="mage.deck.HistoricalType2"/>
|
||||
<deckType name="Constructed - Super Type 2" jar="mage-deck-constructed.jar" className="mage.deck.SuperType2"/>
|
||||
<deckType name="Constructed - Australian Highlander" jar="mage-deck-constructed.jar" className="mage.deck.AusHighlander"/>
|
||||
<deckType name="Constructed - Canadian Highlander" jar="mage-deck-constructed.jar" className="mage.deck.CanadianHighlander"/>
|
||||
<deckType name="Constructed - Old School 93/94" jar="mage-deck-constructed.jar" className="mage.deck.OldSchool9394"/>
|
||||
<deckType name="Constructed - Old School 93/94 - Italian Rules" jar="mage-deck-constructed.jar" className="mage.deck.OldSchool9394Italian"/>
|
||||
<deckType name="Constructed - Old School 93/94 - Channel Fireball Rules" jar="mage-deck-constructed.jar" className="mage.deck.OldSchool9394CFB"/>
|
||||
<deckType name="Constructed - Old School 93/94 - EudoGames Rules" jar="mage-deck-constructed.jar" className="mage.deck.OldSchool9394EG"/>
|
||||
<deckType name="Constructed - Old School 93/94 - EC Rules" jar="mage-deck-constructed.jar" className="mage.deck.OldSchool9394EC"/>
|
||||
<deckType name="Constructed - Premodern" jar="mage-deck-constructed.jar" className="mage.deck.Premodern"/>
|
||||
<deckType name="Constructed - Freeform" jar="mage-deck-constructed.jar" className="mage.deck.Freeform"/>
|
||||
<deckType name="Variant Magic - Commander" jar="mage-deck-constructed.jar" className="mage.deck.Commander"/>
|
||||
<deckType name="Variant Magic - Duel Commander" jar="mage-deck-constructed.jar" className="mage.deck.DuelCommander"/>
|
||||
<deckType name="Variant Magic - MTGO 1v1 Commander" jar="mage-deck-constructed.jar" className="mage.deck.MTGO1v1Commander"/>
|
||||
<deckType name="Variant Magic - Centurion Commander" jar="mage-deck-constructed.jar" className="mage.deck.CenturionCommander"/>
|
||||
<deckType name="Variant Magic - Tiny Leaders" jar="mage-deck-constructed.jar" className="mage.deck.TinyLeaders"/>
|
||||
<deckType name="Variant Magic - Momir Basic" jar="mage-deck-constructed.jar" className="mage.deck.Momir"/>
|
||||
<deckType name="Variant Magic - Penny Dreadful Commander" jar="mage-deck-constructed.jar" className="mage.deck.PennyDreadfulCommander"/>
|
||||
<deckType name="Variant Magic - Freeform Commander" jar="mage-deck-constructed.jar" className="mage.deck.FreeformCommander"/>
|
||||
<deckType name="Variant Magic - Freeform Unlimited Commander" jar="mage-deck-constructed.jar" className="mage.deck.FreeformUnlimitedCommander"/>
|
||||
<deckType name="Variant Magic - Brawl" jar="mage-deck-constructed.jar" className="mage.deck.Brawl"/>
|
||||
<deckType name="Variant Magic - Oathbreaker" jar="mage-deck-constructed.jar" className="mage.deck.Oathbreaker"/>
|
||||
<deckType name="Block Constructed - Amonkhet" jar="mage-deck-constructed.jar" className="mage.deck.AmonkhetBlock"/>
|
||||
<deckType name="Block Constructed - Battle for Zendikar" jar="mage-deck-constructed.jar" className="mage.deck.BattleForZendikarBlock"/>
|
||||
<deckType name="Block Constructed - Innistrad" jar="mage-deck-constructed.jar" className="mage.deck.InnistradBlock"/>
|
||||
<deckType name="Block Constructed - Ixalan" jar="mage-deck-constructed.jar" className="mage.deck.IxalanBlock"/>
|
||||
<deckType name="Block Constructed - Kaladesh" jar="mage-deck-constructed.jar" className="mage.deck.KaladeshBlock"/>
|
||||
<deckType name="Block Constructed - Kamigawa" jar="mage-deck-constructed.jar" className="mage.deck.KamigawaBlock"/>
|
||||
<deckType name="Block Constructed - Khans of Tarkir" jar="mage-deck-constructed.jar" className="mage.deck.KhansOfTarkirBlock"/>
|
||||
<deckType name="Block Constructed - Lorwyn" jar="mage-deck-constructed.jar" className="mage.deck.LorwynBlock"/>
|
||||
<deckType name="Block Constructed - Return to Ravnica" jar="mage-deck-constructed.jar" className="mage.deck.ReturnToRavnicaBlock"/>
|
||||
<deckType name="Block Constructed - Scars of Mirrodin" jar="mage-deck-constructed.jar" className="mage.deck.ScarsOfMirrodinBlock"/>
|
||||
<deckType name="Block Constructed - Shadowmoor" jar="mage-deck-constructed.jar" className="mage.deck.ShadowmoorBlock"/>
|
||||
<deckType name="Block Constructed - Shadows over Innistrad" jar="mage-deck-constructed.jar" className="mage.deck.ShadowsOverInnistradBlock"/>
|
||||
<deckType name="Block Constructed - Shards of Alara" jar="mage-deck-constructed.jar" className="mage.deck.ShardsOfAlaraBlock"/>
|
||||
<deckType name="Block Constructed - Theros" jar="mage-deck-constructed.jar" className="mage.deck.TherosBlock"/>
|
||||
<deckType name="Block Constructed - Zendikar" jar="mage-deck-constructed.jar" className="mage.deck.ZendikarBlock"/>
|
||||
<deckType name="Block Constructed Custom - Star Wars" jar="mage-deck-constructed.jar" className="mage.deck.StarWarsBlock"/>
|
||||
<deckType name="Limited" jar="mage-deck-limited.jar" className="mage.deck.Limited"/>
|
||||
</deckTypes>
|
||||
</config>
|
|
@ -32,7 +32,7 @@ public final class AgonyWarp extends CardImpl {
|
|||
|
||||
// Target creature gets -0/-3 until end of turn.
|
||||
Effect effect2 = new BoostTargetEffect(-0,-3, Duration.EndOfTurn);
|
||||
effect2.setText("<br></br>Target creature gets -0/-3 until end of turn");
|
||||
effect2.setText("<br><br>Target creature gets -0/-3 until end of turn");
|
||||
effect2.setTargetPointer(SecondTargetPointer.getInstance());
|
||||
this.getSpellAbility().addEffect(effect2);
|
||||
target = new TargetCreaturePermanent(new FilterCreaturePermanent("second creature (can be the same as the first)"));
|
||||
|
|
|
@ -78,7 +78,18 @@ class ArchelosLagoonMysticEffect extends ReplacementEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
return !source.getSourceId().equals(((EntersTheBattlefieldEvent) event).getTarget().getId());
|
||||
Permanent sourceObject = game.getPermanent(source.getSourceId());
|
||||
if (sourceObject == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permanent targetObject = ((EntersTheBattlefieldEvent) event).getTarget();
|
||||
if (targetObject == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !sourceObject.getId().equals(targetObject.getId())
|
||||
&& sourceObject.isTapped() == this.tapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -68,6 +68,6 @@ enum ArcticFoxesCondition implements Condition {
|
|||
if (defenderId == null) {
|
||||
return false;
|
||||
}
|
||||
return game.getBattlefield().contains(filter, defenderId, 1, game);
|
||||
return game.getBattlefield().contains(filter, source.getSourceId(), defenderId, game, 1);
|
||||
}
|
||||
}
|
|
@ -33,7 +33,7 @@ public final class AzoriusPloy extends CardImpl {
|
|||
|
||||
// Prevent all combat damage that would be dealt to target creature this turn.
|
||||
Effect effect2 = new PreventDamageToTargetEffect(Duration.EndOfTurn, true);
|
||||
effect2.setText("<br></br>Prevent all combat damage that would be dealt to target creature this turn.");
|
||||
effect2.setText("<br><br>Prevent all combat damage that would be dealt to target creature this turn.");
|
||||
effect2.setTargetPointer(SecondTargetPointer.getInstance());
|
||||
this.getSpellAbility().addEffect(effect2);
|
||||
target = new TargetCreaturePermanent(new FilterCreaturePermanent("second creature (can be the same as the first)"));
|
||||
|
|
|
@ -63,16 +63,15 @@ class BacklashEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
boolean applied = false;
|
||||
Permanent targetCreature = game.getPermanent(targetPointer.getFirst(game, source));
|
||||
if (targetCreature != null) {
|
||||
applied = targetCreature.tap(source, game);
|
||||
targetCreature.tap(source, game);
|
||||
Player controller = game.getPlayer(targetCreature.getControllerId());
|
||||
if (controller != null) {
|
||||
controller.damage(targetCreature.getPower().getValue(), source.getSourceId(), source, game);
|
||||
applied = true;
|
||||
controller.damage(targetCreature.getPower().getValue(), targetCreature.getId(), source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return applied;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.cards.b;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.counter.DistributeCountersEffect;
|
||||
import mage.abilities.keyword.MiracleAbility;
|
||||
|
@ -11,15 +9,15 @@ import mage.constants.CardType;
|
|||
import mage.counters.CounterType;
|
||||
import mage.target.common.TargetCreaturePermanentAmount;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author North
|
||||
*/
|
||||
public final class BlessingsOfNature extends CardImpl {
|
||||
|
||||
public BlessingsOfNature(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{G}");
|
||||
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}");
|
||||
|
||||
// Distribute four +1/+1 counters among any number of target creatures.
|
||||
this.getSpellAbility().addEffect(new DistributeCountersEffect(CounterType.P1P1, 4, false, "any number of target creatures"));
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.StateTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
|
@ -11,7 +8,6 @@ import mage.abilities.effects.OneShotEffect;
|
|||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import static mage.cards.c.CityInABottle.getArabianNightsNamePredicates;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
|
@ -23,11 +19,15 @@ import mage.filter.predicate.mageobject.NamePredicate;
|
|||
import mage.filter.predicate.permanent.TokenPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static mage.cards.c.CityInABottle.getArabianNightsNamePredicates;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public final class CityInABottle extends CardImpl {
|
||||
|
@ -158,7 +158,7 @@ class CityInABottleStateTriggeredAbility extends StateTriggeredAbility {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
return game.getBattlefield().contains(filter, this.getControllerId(), game, 1);
|
||||
return game.getBattlefield().contains(filter, this.getSourceId(), this.getControllerId(), game, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.cards.c;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
|
@ -18,14 +16,15 @@ import mage.filter.predicate.mageobject.AbilityPredicate;
|
|||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public final class ConcertedEffort extends CardImpl {
|
||||
|
||||
public ConcertedEffort(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}");
|
||||
|
||||
// At the beginning of each upkeep, creatures you control gain flying until end of turn if a creature you control has flying. The same is true for fear, first strike, double strike, landwalk, protection, trample, and vigilance.
|
||||
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ConcertedEffortEffect(), TargetController.ANY, false));
|
||||
|
@ -81,22 +80,22 @@ class ConcertedEffortEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
// Flying
|
||||
if (game.getBattlefield().contains(filterFlying, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().contains(filterFlying, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Fear
|
||||
if (game.getBattlefield().contains(filterFear, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().contains(filterFear, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(FearAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// First strike
|
||||
if (game.getBattlefield().contains(filterFirstStrike, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().contains(filterFirstStrike, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Double strike
|
||||
if (game.getBattlefield().contains(filterDoubleStrike, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().contains(filterDoubleStrike, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
|
@ -119,12 +118,12 @@ class ConcertedEffortEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
// Trample
|
||||
if (game.getBattlefield().contains(filterTrample, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().contains(filterTrample, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Vigilance
|
||||
if (game.getBattlefield().contains(filterVigilance, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().contains(filterVigilance, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -70,18 +70,19 @@ class CourtOfAmbitionEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
int discardCount = source.isControlledBy(game.getMonarchId()) ? 2 : 1;
|
||||
String message = "Discard " + CardUtil.numberToText(discardCount, "a")
|
||||
+ "card" + (discardCount > 1 ? 's' : "") + "? If not you lose " + (discardCount * 3) + " life";
|
||||
+ " card" + (discardCount > 1 ? 's' : "") + "? If not you lose " + (discardCount * 3) + " life";
|
||||
Map<UUID, Cards> discardMap = new HashMap<>();
|
||||
for (UUID playerId : game.getOpponents(source.getControllerId())) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player == null) {
|
||||
continue;
|
||||
}
|
||||
if (player.getHand().size() < discardCount || !player.chooseUse(outcome, message, source, game)) {
|
||||
if (player.getHand().size() < discardCount || !player.chooseUse(Outcome.LoseLife, message, source, game)) {
|
||||
player.loseLife(discardCount * 3, game, source, false);
|
||||
continue;
|
||||
}
|
||||
TargetDiscard target = new TargetDiscard(discardCount, StaticFilters.FILTER_CARD, playerId);
|
||||
player.choose(outcome, target, source.getSourceId(), game);
|
||||
player.choose(Outcome.Discard, target, source.getSourceId(), game);
|
||||
discardMap.put(playerId, new CardsImpl(target.getTargets()));
|
||||
}
|
||||
for (Map.Entry<UUID, Cards> entry : discardMap.entrySet()) {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.cards.c;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
|
@ -12,27 +10,30 @@ import mage.constants.ComparisonType;
|
|||
import mage.constants.TargetController;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterNonlandPermanent;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.filter.predicate.ObjectSourcePlayer;
|
||||
import mage.filter.predicate.ObjectSourcePlayerPredicate;
|
||||
import mage.filter.predicate.mageobject.ConvertedManaCostPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author cg5
|
||||
*/
|
||||
public final class CullingScales extends CardImpl {
|
||||
|
||||
private static final FilterPermanent filterNonlandPermanentWithLowestCmc = new FilterNonlandPermanent(
|
||||
"nonland permanent with the lowest converted mana cost (<i>If two or more permanents are tied for lowest cost, target any one of them.</i>)"
|
||||
"nonland permanent with the lowest converted mana cost (<i>If two or more permanents are tied for lowest cost, target any one of them.</i>)"
|
||||
);
|
||||
|
||||
static {
|
||||
filterNonlandPermanentWithLowestCmc.add(new HasLowestCMCAmongstNonlandPermanentsPredicate());
|
||||
}
|
||||
|
||||
|
||||
public CullingScales(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
|
||||
|
||||
// At the beginning of your upkeep, destroy target nonland permanent with the lowest converted mana cost.
|
||||
Ability ability = new BeginningOfUpkeepTriggeredAbility(new DestroyTargetEffect(), TargetController.YOU, false);
|
||||
|
@ -48,16 +49,16 @@ public final class CullingScales extends CardImpl {
|
|||
public CullingScales copy() {
|
||||
return new CullingScales(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class HasLowestCMCAmongstNonlandPermanentsPredicate implements Predicate<Permanent> {
|
||||
|
||||
class HasLowestCMCAmongstNonlandPermanentsPredicate implements ObjectSourcePlayerPredicate<ObjectSourcePlayer<Permanent>> {
|
||||
|
||||
@Override
|
||||
public boolean apply(Permanent input, Game game) {
|
||||
public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) {
|
||||
FilterPermanent filter = new FilterNonlandPermanent();
|
||||
filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, input.getConvertedManaCost()));
|
||||
return !game.getBattlefield().contains(filter, 1, game);
|
||||
filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, input.getObject().getConvertedManaCost()));
|
||||
return !game.getBattlefield().contains(filter, input.getSourceId(), input.getPlayerId(), game, 1);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -84,7 +84,7 @@ class DoomForetoldEffect extends OneShotEffect {
|
|||
}
|
||||
FilterPermanent filter2 = filter.copy();
|
||||
filter2.add(new ControllerIdPredicate(player.getId()));
|
||||
if (game.getBattlefield().contains(filter2, 1, game)) {
|
||||
if (game.getBattlefield().contains(filter2, source, game, 1)) {
|
||||
TargetPermanent target = new TargetPermanent(filter2);
|
||||
target.setNotTarget(true);
|
||||
if (player.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.cards.h;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
|
@ -24,14 +22,15 @@ import mage.filter.predicate.mageobject.NamePredicate;
|
|||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public final class HedronAlignment extends CardImpl {
|
||||
|
||||
public HedronAlignment(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
|
||||
|
||||
// Hexproof
|
||||
this.addAbility(HexproofAbility.getInstance());
|
||||
|
@ -85,7 +84,7 @@ class HedronAlignmentEffect extends OneShotEffect {
|
|||
Cards cardsToReveal = new CardsImpl();
|
||||
controller.revealCards(sourceObject.getIdName(), cardsToReveal, game);
|
||||
// Check battlefield
|
||||
if (!game.getBattlefield().contains(filterPermanent, source.getControllerId(), game, 1)) {
|
||||
if (!game.getBattlefield().contains(filterPermanent, source, game, 1)) {
|
||||
return true;
|
||||
}
|
||||
if (controller.getHand().getCards(filterCard, source.getSourceId(), controller.getId(), game).isEmpty()) {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.cards.h;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
|
||||
|
@ -17,12 +15,7 @@ import mage.abilities.keyword.CumulativeUpkeepAbility;
|
|||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterControlledLandPermanent;
|
||||
import mage.filter.common.FilterLandPermanent;
|
||||
|
@ -34,13 +27,15 @@ import mage.target.Target;
|
|||
import mage.target.TargetPermanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public final class HeraldOfLeshrac extends CardImpl {
|
||||
|
||||
private static final FilterPermanent filter = new FilterControlledLandPermanent("land you control but don't own");
|
||||
|
||||
static {
|
||||
filter.add(TargetController.NOT_YOU.getOwnerPredicate());
|
||||
}
|
||||
|
@ -78,6 +73,7 @@ public final class HeraldOfLeshrac extends CardImpl {
|
|||
class HeraldOfLeshracCumulativeCost extends CostImpl {
|
||||
|
||||
private static final FilterPermanent filter = new FilterLandPermanent("land you don't control");
|
||||
|
||||
static {
|
||||
filter.add(TargetController.NOT_YOU.getControllerPredicate());
|
||||
}
|
||||
|
@ -105,7 +101,7 @@ class HeraldOfLeshracCumulativeCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return game.getBattlefield().contains(filter, controllerId, game, 1);
|
||||
return game.getBattlefield().contains(filter, source.getSourceId(), controllerId, game, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
|
||||
package mage.cards.i;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.PreventDamageToAttachedEffect;
|
||||
import mage.abilities.keyword.EnchantAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author L_J
|
||||
*/
|
||||
public final class Inviolability extends CardImpl {
|
||||
|
@ -34,7 +28,9 @@ public final class Inviolability extends CardImpl {
|
|||
this.addAbility(new EnchantAbility(auraTarget.getTargetName()));
|
||||
|
||||
// Prevent all damage that would be dealt to enchanted creature.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PreventDamageToAttachedEffect(Duration.WhileOnBattlefield, AttachmentType.EQUIPMENT, false)));
|
||||
this.addAbility(new SimpleStaticAbility(new PreventDamageToAttachedEffect(
|
||||
Duration.WhileOnBattlefield, AttachmentType.AURA, false
|
||||
)));
|
||||
}
|
||||
|
||||
public Inviolability(final Inviolability card) {
|
||||
|
|
|
@ -103,62 +103,62 @@ class MajesticMyriarchEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
|
||||
// Flying
|
||||
if (game.getBattlefield().contains(filterFlying, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterFlying, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), source);
|
||||
}
|
||||
|
||||
// First strike
|
||||
if (game.getBattlefield().contains(filterFirstStrike, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterFirstStrike, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), source);
|
||||
}
|
||||
|
||||
// Double strike
|
||||
if (game.getBattlefield().contains(filterDoubleStrike, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterDoubleStrike, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn), source);
|
||||
}
|
||||
|
||||
// Deathtouch
|
||||
if (game.getBattlefield().contains(filterDeathtouch, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterDeathtouch, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn), source);
|
||||
}
|
||||
|
||||
// Haste
|
||||
if (game.getBattlefield().contains(filterHaste, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterHaste, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.EndOfTurn), source);
|
||||
}
|
||||
|
||||
// Hexproof
|
||||
if (game.getBattlefield().contains(filterHexproof, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterHexproof, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(HexproofAbility.getInstance(), Duration.EndOfTurn), source);
|
||||
}
|
||||
|
||||
// Indestructible
|
||||
if (game.getBattlefield().contains(filterIndestructible, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterIndestructible, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), source);
|
||||
}
|
||||
|
||||
// Lifelink
|
||||
if (game.getBattlefield().contains(filterLifelink, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterLifelink, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn), source);
|
||||
}
|
||||
|
||||
// Menace
|
||||
if (game.getBattlefield().contains(filterMenace, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterMenace, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(new MenaceAbility(), Duration.EndOfTurn), source);
|
||||
}
|
||||
|
||||
// Reach
|
||||
if (game.getBattlefield().contains(filterReach, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterReach, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(ReachAbility.getInstance(), Duration.EndOfTurn), source);
|
||||
}
|
||||
|
||||
// Trample
|
||||
if (game.getBattlefield().contains(filterTrample, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterTrample, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), source);
|
||||
}
|
||||
|
||||
// Vigilance
|
||||
if (game.getBattlefield().contains(filterVigilance, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterVigilance, source, game, 1)) {
|
||||
game.addEffect(new GainAbilitySourceEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn), source);
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -32,7 +32,7 @@ public final class MartialGlory extends CardImpl {
|
|||
|
||||
// Target creature gets +0/+3 until end of turn.
|
||||
Effect effect2 = new BoostTargetEffect(0,3, Duration.EndOfTurn);
|
||||
effect2.setText("<br></br>Target creature gets +0/+3 until end of turn");
|
||||
effect2.setText("<br><br>Target creature gets +0/+3 until end of turn");
|
||||
effect2.setTargetPointer(SecondTargetPointer.getInstance());
|
||||
target = new TargetCreaturePermanent(new FilterCreaturePermanent("second creature (can be the same as the first)"));
|
||||
this.getSpellAbility().addEffect(effect2);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.cards.o;
|
||||
|
||||
import mage.MageInt;
|
||||
|
@ -94,67 +93,67 @@ class OdricLunarchMarshalEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
|
||||
// First strike
|
||||
if (game.getBattlefield().contains(filterFirstStrike, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterFirstStrike, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Flying
|
||||
if (game.getBattlefield().contains(filterFlying, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterFlying, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Deathtouch
|
||||
if (game.getBattlefield().contains(filterDeathtouch, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterDeathtouch, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Double strike
|
||||
if (game.getBattlefield().contains(filterDoubleStrike, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterDoubleStrike, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Haste
|
||||
if (game.getBattlefield().contains(filterHaste, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterHaste, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Hexproof
|
||||
if (game.getBattlefield().contains(filterHexproof, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterHexproof, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(HexproofAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Indestructible
|
||||
if (game.getBattlefield().contains(filterIndestructible, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterIndestructible, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Lifelink
|
||||
if (game.getBattlefield().contains(filterLifelink, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterLifelink, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Menace
|
||||
if (game.getBattlefield().contains(filterMenace, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterMenace, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(new MenaceAbility(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Reach
|
||||
if (game.getBattlefield().contains(filterReach, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterReach, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(ReachAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Skulk
|
||||
if (game.getBattlefield().contains(filterSkulk, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterSkulk, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(new SkulkAbility(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Trample
|
||||
if (game.getBattlefield().contains(filterTrample, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterTrample, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
|
||||
// Vigilance
|
||||
if (game.getBattlefield().contains(filterVigilance, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filterVigilance, source, game, 1)) {
|
||||
game.addEffect(new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, filterCreatures), source);
|
||||
}
|
||||
return true;
|
||||
|
|
59
Mage.Sets/src/mage/cards/r/Realmwalker.java
Normal file
59
Mage.Sets/src/mage/cards/r/Realmwalker.java
Normal file
|
@ -0,0 +1,59 @@
|
|||
package mage.cards.r;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.AsEntersBattlefieldAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.ChooseCreatureTypeEffect;
|
||||
import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect;
|
||||
import mage.abilities.effects.common.continuous.PlayTheTopCardEffect;
|
||||
import mage.abilities.keyword.ChangelingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.filter.predicate.mageobject.ChosenSubtypePredicate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author weirddan455
|
||||
*/
|
||||
public final class Realmwalker extends CardImpl {
|
||||
|
||||
private static final FilterCreatureCard filter = new FilterCreatureCard("cast creature spells of the chosen type");
|
||||
static {
|
||||
filter.add(ChosenSubtypePredicate.instance);
|
||||
}
|
||||
|
||||
public Realmwalker(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}");
|
||||
|
||||
this.subtype.add(SubType.SHAPESHIFTER);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Changeling
|
||||
this.setIsAllCreatureTypes(true);
|
||||
this.addAbility(ChangelingAbility.getInstance());
|
||||
|
||||
// As Realmwalker enters the battlefield, choose a creature type.
|
||||
this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Benefit)));
|
||||
|
||||
// You may look at the top card of your library any time.
|
||||
this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect()));
|
||||
|
||||
// You may cast creature spells of the chosen type from the top of your library.
|
||||
this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter)));
|
||||
}
|
||||
|
||||
private Realmwalker(final Realmwalker card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Realmwalker copy() {
|
||||
return new Realmwalker(this);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.cards.r;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.CardImpl;
|
||||
|
@ -16,14 +14,15 @@ import mage.players.Player;
|
|||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetOpponent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public final class RemorselessPunishment extends CardImpl {
|
||||
|
||||
public RemorselessPunishment(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}{B}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}");
|
||||
|
||||
// Target opponent loses 5 life unless that player discards two cards or sacrifices a creature or planeswalker. Repeat this process once.
|
||||
getSpellAbility().addEffect(new RemorselessPunishmentEffect());
|
||||
|
@ -80,7 +79,7 @@ class RemorselessPunishmentEffect extends OneShotEffect {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (game.getBattlefield().contains(filter, opponent.getId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filter, source.getSourceId(), opponent.getId(), game, 1)) {
|
||||
if (opponent.chooseUse(outcome, "Choose your " + iteration + " punishment.", null, "Sacrifice a creature or planeswalker", "Lose 5 life", source, game)) {
|
||||
TargetPermanent target = new TargetPermanent(1, 1, filter, true);
|
||||
if (target.choose(Outcome.Sacrifice, opponent.getId(), source.getId(), game)) {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.cards.s;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
|
@ -11,8 +9,8 @@ import mage.abilities.keyword.TrampleAbility;
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
|
@ -22,8 +20,9 @@ import mage.players.Player;
|
|||
import mage.target.Target;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public final class ShelteringAncient extends CardImpl {
|
||||
|
@ -82,7 +81,7 @@ class ShelteringAncientCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return game.getBattlefield().contains(filter, source.getSourceId(), game, 1);
|
||||
return game.getBattlefield().contains(filter, source, game, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
98
Mage.Sets/src/mage/cards/s/SurtlandElementalist.java
Normal file
98
Mage.Sets/src/mage/cards/s/SurtlandElementalist.java
Normal file
|
@ -0,0 +1,98 @@
|
|||
package mage.cards.s;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.ApprovingObject;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.costs.OrCost;
|
||||
import mage.abilities.costs.common.RevealTargetFromHandCost;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author weirddan455
|
||||
*/
|
||||
public final class SurtlandElementalist extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("a Giant card from your hand");
|
||||
static {
|
||||
filter.add(SubType.GIANT.getPredicate());
|
||||
}
|
||||
|
||||
public SurtlandElementalist(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}");
|
||||
|
||||
this.subtype.add(SubType.GIANT);
|
||||
this.subtype.add(SubType.WIZARD);
|
||||
this.power = new MageInt(8);
|
||||
this.toughness = new MageInt(8);
|
||||
|
||||
// As an additional cost to cast this spell, reveal a Giant card from your hand or pay {2}.
|
||||
this.getSpellAbility().addCost(new OrCost(
|
||||
new RevealTargetFromHandCost(new TargetCardInHand(filter)),
|
||||
new GenericManaCost(2),
|
||||
"reveal a Giant card from your hand or pay {2}"));
|
||||
|
||||
// Whenever Surtland Elementalist attacks, you may cast an instant or sorcery spell from your hand without paying its mana cost.
|
||||
this.addAbility(new AttacksTriggeredAbility(new SurtlandElementalistEffect(), true));
|
||||
}
|
||||
|
||||
private SurtlandElementalist(final SurtlandElementalist card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurtlandElementalist copy() {
|
||||
return new SurtlandElementalist(this);
|
||||
}
|
||||
}
|
||||
|
||||
class SurtlandElementalistEffect extends OneShotEffect {
|
||||
|
||||
public SurtlandElementalistEffect () {
|
||||
super(Outcome.PlayForFree);
|
||||
this.staticText = "cast an instant or sorcery spell from your hand without paying its mana cost";
|
||||
}
|
||||
|
||||
private SurtlandElementalistEffect(final SurtlandElementalistEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurtlandElementalistEffect copy() {
|
||||
return new SurtlandElementalistEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player != null) {
|
||||
TargetCardInHand target = new TargetCardInHand(0, 1, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY);
|
||||
if (player.chooseTarget(Outcome.PlayForFree, target, source, game)) {
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
|
||||
boolean cardWasCast = player.cast(player.chooseAbilityForCast(card, game, true),
|
||||
game, true, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
|
||||
return cardWasCast;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.cards.t;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
|
||||
|
@ -18,8 +16,9 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class TheCheeseStandsAlone extends CardImpl {
|
||||
|
@ -47,6 +46,7 @@ class CheeseStandsAloneContinuousEffect extends ContinuousRuleModifyingEffectImp
|
|||
private static final FilterControlledPermanent filter = new FilterControlledPermanent();
|
||||
|
||||
private boolean wonAlready = false;
|
||||
|
||||
static {
|
||||
filter.add(new NamePredicate("The Cheese Stands Alone"));
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ class CheeseStandsAloneContinuousEffect extends ContinuousRuleModifyingEffectImp
|
|||
}
|
||||
|
||||
public CheeseStandsAloneContinuousEffect(final CheeseStandsAloneContinuousEffect effect) {
|
||||
super(effect);
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -72,7 +72,7 @@ class CheeseStandsAloneContinuousEffect extends ContinuousRuleModifyingEffectImp
|
|||
if (controller.getHand().isEmpty()) {
|
||||
int numberPerms = new PermanentsOnBattlefieldCount(new FilterControlledPermanent()).calculate(game, source, this);
|
||||
if (numberPerms == 1) {
|
||||
if (game.getBattlefield().contains(filter, source.getControllerId(), 1, game)) {
|
||||
if (game.getBattlefield().containsControlled(filter, source, game, 1)) {
|
||||
if (!wonAlready) {
|
||||
wonAlready = true;
|
||||
controller.won(game);
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
package mage.cards.t;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.StateTriggeredAbility;
|
||||
|
@ -31,8 +29,9 @@ import mage.filter.predicate.mageobject.NamePredicate;
|
|||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LoneFox
|
||||
*/
|
||||
public final class TidalInfluence extends CardImpl {
|
||||
|
@ -44,26 +43,26 @@ public final class TidalInfluence extends CardImpl {
|
|||
}
|
||||
|
||||
public TidalInfluence(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
|
||||
|
||||
// Cast Tidal Influence only if no permanents named Tidal Influence are on the battlefield.
|
||||
this.getSpellAbility().addCost(new TidalInfluenceCost());
|
||||
// Tidal Influence enters the battlefield with a tide counter on it.
|
||||
this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()),
|
||||
"with a tide counter on it."));
|
||||
"with a tide counter on it."));
|
||||
// At the beginning of your upkeep, put a tide counter on Tidal Influence.
|
||||
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()),
|
||||
TargetController.YOU, false));
|
||||
TargetController.YOU, false));
|
||||
// As long as there is exactly one tide counter on Tidal Influence, all blue creatures get -2/-0.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
|
||||
new BoostAllEffect(-2, -0, Duration.WhileOnBattlefield, filter, false),
|
||||
new SourceHasCounterCondition(CounterType.TIDE, 1, 1),
|
||||
"As long as there is exactly one tide counter on {this}, all blue creatures get -2/-0.")));
|
||||
new BoostAllEffect(-2, -0, Duration.WhileOnBattlefield, filter, false),
|
||||
new SourceHasCounterCondition(CounterType.TIDE, 1, 1),
|
||||
"As long as there is exactly one tide counter on {this}, all blue creatures get -2/-0.")));
|
||||
// As long as there are exactly three tide counters on Tidal Influence, all blue creatures get +2/+0.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
|
||||
new BoostAllEffect(2, -0, Duration.WhileOnBattlefield, filter, false),
|
||||
new SourceHasCounterCondition(CounterType.TIDE, 3, 3),
|
||||
"As long as there are exactly three tide counter on {this}, all blue creatures get +2/-0.")));
|
||||
new BoostAllEffect(2, -0, Duration.WhileOnBattlefield, filter, false),
|
||||
new SourceHasCounterCondition(CounterType.TIDE, 3, 3),
|
||||
"As long as there are exactly three tide counter on {this}, all blue creatures get +2/-0.")));
|
||||
// Whenever there are four tide counters on Tidal Influence, remove all tide counters from it.
|
||||
this.addAbility(new TidalInfluenceTriggeredAbility(new RemoveAllCountersSourceEffect(CounterType.TIDE)));
|
||||
}
|
||||
|
@ -97,7 +96,7 @@ class TidalInfluenceCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return !game.getBattlefield().contains(filter, 1, game);
|
||||
return !game.getBattlefield().contains(filter, source, game, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
|
||||
package mage.cards.t;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AsEntersBattlefieldAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.AttachEffect;
|
||||
import mage.abilities.effects.common.ChooseCreatureTypeEffect;
|
||||
import mage.abilities.effects.common.ChooseLandTypeEffect;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
|
||||
|
@ -15,24 +15,24 @@ import mage.abilities.keyword.EnchantAbility;
|
|||
import mage.abilities.keyword.LandwalkAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.filter.common.FilterLandPermanent;
|
||||
import mage.filter.predicate.mageobject.ChosenSubtypePredicate;
|
||||
import mage.filter.predicate.ObjectSourcePlayer;
|
||||
import mage.filter.predicate.ObjectSourcePlayerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public final class TravelersCloak extends CardImpl {
|
||||
|
||||
public TravelersCloak(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
|
||||
this.subtype.add(SubType.AURA);
|
||||
|
||||
// Enchant creature
|
||||
|
@ -41,18 +41,17 @@ public final class TravelersCloak extends CardImpl {
|
|||
this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility));
|
||||
Ability ability = new EnchantAbility(auraTarget.getTargetName());
|
||||
this.addAbility(ability);
|
||||
|
||||
|
||||
// As Traveler's Cloak enters the battlefield, choose a land type.
|
||||
this.addAbility(new AsEntersBattlefieldAbility(new ChooseLandTypeEffect(Outcome.AddAbility)));
|
||||
|
||||
|
||||
// When Traveler's Cloak enters the battlefield, draw a card.
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false));
|
||||
|
||||
|
||||
// Enchanted creature has landwalk of the chosen type.
|
||||
FilterLandPermanent filter = new FilterLandPermanent("Landwalk of the chosen type");
|
||||
filter.add(ChosenSubtypePredicate.instance);
|
||||
Ability landwalkAbility = new LandwalkAbility(filter);
|
||||
Effect effect = new GainAbilityAttachedEffect(landwalkAbility, AttachmentType.AURA);
|
||||
filter.add(TravelersCloakChosenSubtypePredicate.instance);
|
||||
Effect effect = new TravelersCloakGainAbilityAttachedEffect(filter);
|
||||
effect.setText("Enchanted creature has landwalk of the chosen type");
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
|
||||
}
|
||||
|
@ -66,3 +65,35 @@ public final class TravelersCloak extends CardImpl {
|
|||
return new TravelersCloak(this);
|
||||
}
|
||||
}
|
||||
|
||||
class TravelersCloakGainAbilityAttachedEffect extends GainAbilityAttachedEffect {
|
||||
|
||||
public TravelersCloakGainAbilityAttachedEffect(FilterLandPermanent filter) {
|
||||
super(new LandwalkAbility(filter), AttachmentType.AURA);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterGain(Game game, Ability source, Permanent permanent, Ability addedAbility) {
|
||||
super.afterGain(game, source, permanent, addedAbility);
|
||||
|
||||
// ChooseLandTypeEffect keep settings in original source, but we must transfer it to real permanent
|
||||
Object val = game.getState().getValue(source.getSourceId() + "_type");
|
||||
game.getState().setValue(permanent.getId() + "_landwalk_type", val);
|
||||
}
|
||||
}
|
||||
|
||||
enum TravelersCloakChosenSubtypePredicate implements ObjectSourcePlayerPredicate<ObjectSourcePlayer<MageObject>> {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) {
|
||||
SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(input.getSourceId(), game, "_landwalk_type");
|
||||
return input.getObject().hasSubtype(subType, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Chosen subtype";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,8 @@ class VivienMonstersAdvocateTokenEffect extends OneShotEffect {
|
|||
if (permanent == null) {
|
||||
continue;
|
||||
}
|
||||
Choice choice = new ChoiceImpl();
|
||||
Choice choice = new ChoiceImpl(true);
|
||||
choice.setMessage("Choose vigilance, reach, or trample counter");
|
||||
choice.setChoices(choices);
|
||||
player.choose(outcome, choice, game);
|
||||
String chosen = choice.getChoice();
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
package mage.cards.w;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
|
@ -25,8 +21,12 @@ import mage.target.TargetPermanent;
|
|||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public final class WeightOfConscience extends CardImpl {
|
||||
|
@ -84,8 +84,8 @@ class WeightOfConscienceEffect extends OneShotEffect {
|
|||
// It was not blinked, use the standard method
|
||||
enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
}
|
||||
if (controller != null
|
||||
&& enchantment != null
|
||||
if (controller != null
|
||||
&& enchantment != null
|
||||
&& enchantment.getAttachedTo() != null) {
|
||||
Permanent creature = game.getPermanent(enchantment.getAttachedTo());
|
||||
if (creature != null) {
|
||||
|
@ -119,10 +119,10 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent {
|
|||
if (player != null) {
|
||||
// Choosing first target
|
||||
if (this.getTargets().isEmpty()) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, game)) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, sourceId, game)) {
|
||||
for (SubType subtype : permanent.getSubtype(game)) {
|
||||
if (subtype.getSubTypeSet() == SubTypeSet.CreatureType) {
|
||||
if (game.getBattlefield().contains(new FilterControlledCreaturePermanent(subtype, subtype.toString()), sourceControllerId, game, 2)) {
|
||||
if (game.getBattlefield().contains(new FilterControlledCreaturePermanent(subtype, subtype.toString()), sourceId, sourceControllerId, game, 2)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent {
|
|||
UUID firstTargetId = this.getTargets().get(0);
|
||||
Permanent firstTargetCreature = game.getPermanent(firstTargetId);
|
||||
if (firstTargetCreature != null) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, game)) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, sourceId, game)) {
|
||||
if (!permanent.getId().equals(firstTargetId) && firstTargetCreature.shareCreatureTypes(permanent, game)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
|
@ -146,8 +146,8 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent {
|
|||
|
||||
@Override
|
||||
public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) {
|
||||
for (Permanent permanent1 : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, game)) {
|
||||
for (Permanent permanent2 : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, game)) {
|
||||
for (Permanent permanent1 : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, sourceId, game)) {
|
||||
for (Permanent permanent2 : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, sourceId, game)) {
|
||||
if (!Objects.equals(permanent1, permanent2) && permanent1.shareCreatureTypes(permanent2, game)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -162,10 +162,10 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent {
|
|||
Permanent targetPermanent = game.getPermanent(id);
|
||||
if (targetPermanent != null) {
|
||||
if (this.getTargets().isEmpty()) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterUntapped, source.getControllerId(), game)) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterUntapped, source.getControllerId(), source.getSourceId(), game)) {
|
||||
for (SubType subtype : permanent.getSubtype(game)) {
|
||||
if (subtype.getSubTypeSet() == SubTypeSet.CreatureType) {
|
||||
if (game.getBattlefield().contains(new FilterControlledCreaturePermanent(subtype, subtype.toString()), source.getControllerId(), game, 2)) {
|
||||
if (game.getBattlefield().contains(new FilterControlledCreaturePermanent(subtype, subtype.toString()), source, game, 2)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -173,9 +173,7 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent {
|
|||
}
|
||||
} else {
|
||||
Permanent firstTarget = game.getPermanent(this.getTargets().get(0));
|
||||
if (firstTarget != null && firstTarget.shareCreatureTypes(targetPermanent, game)) {
|
||||
return true;
|
||||
}
|
||||
return firstTarget != null && firstTarget.shareCreatureTypes(targetPermanent, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public final class Wirecat extends CardImpl {
|
|||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
if (permanent.getId().equals(source.getSourceId())) {
|
||||
return game.getBattlefield().contains(StaticFilters.FILTER_ENCHANTMENT_PERMANENT, 1, game);
|
||||
return game.getBattlefield().contains(StaticFilters.FILTER_ENCHANTMENT_PERMANENT, source, game, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -44,9 +44,11 @@ public final class Kaldheim extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Gladewalker Ritualist", 392, Rarity.UNCOMMON, mage.cards.g.GladewalkerRitualist.class));
|
||||
cards.add(new SetCardInfo("Hengegate Pathway", 260, Rarity.RARE, mage.cards.h.HengegatePathway.class));
|
||||
cards.add(new SetCardInfo("Rampage of the Valkyries", 393, Rarity.UNCOMMON, mage.cards.r.RampageOfTheValkyries.class));
|
||||
cards.add(new SetCardInfo("Realmwalker", 188, Rarity.RARE, mage.cards.r.Realmwalker.class));
|
||||
cards.add(new SetCardInfo("Renegade Reaper", 386, Rarity.UNCOMMON, mage.cards.r.RenegadeReaper.class));
|
||||
cards.add(new SetCardInfo("Showdown of the Skalds", 229, Rarity.RARE, mage.cards.s.ShowdownOfTheSkalds.class));
|
||||
cards.add(new SetCardInfo("Starnheim Aspirant", 380, Rarity.UNCOMMON, mage.cards.s.StarnheimAspirant.class));
|
||||
cards.add(new SetCardInfo("Surtland Elementalist", 375, Rarity.RARE, mage.cards.s.SurtlandElementalist.class));
|
||||
cards.add(new SetCardInfo("Surtland Flinger", 377, Rarity.RARE, mage.cards.s.SurtlandFlinger.class));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package org.mage.test.AI.basic;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class TargetAmountAITest extends CardTestPlayerBaseWithAIHelps {
|
||||
|
||||
@Test
|
||||
public void test_AI_ChooseTargets() {
|
||||
// Distribute four +1/+1 counters among any number of target creatures.
|
||||
addCard(Zone.HAND, playerA, "Blessings of Nature", 1); // {4}{G}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 5);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 4); // 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 4); // 2/2
|
||||
|
||||
// ai must choose by special dialog, not full simulation
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Blessings of Nature");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
//setStrictChooseMode(true); // ai must choose
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPowerToughness(playerA, "Balduvian Bears", 2 + 4, 2 + 4); // boost one creature (it's just a choose code, so can be different from simulation results)
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AI_SimulateTargets() {
|
||||
// Distribute four +1/+1 counters among any number of target creatures.
|
||||
addCard(Zone.HAND, playerA, "Blessings of Nature", 1); // {4}{G}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 5);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 4); // 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 4); // 2/2
|
||||
|
||||
// AI must put creatures on own permanents (all in one creature to boost it)
|
||||
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
|
||||
assertPowerToughness(playerA, "Balduvian Bears", 2 + 1, 2 + 1); // boost each possible creatures
|
||||
assertPowerToughness(playerB, "Balduvian Bears", 2, 2); // no boost for enemy
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package org.mage.test.cards.conditional;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
|
@ -7,7 +6,6 @@ import org.junit.Test;
|
|||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class LegendarySorceryTest extends CardTestPlayerBase {
|
||||
|
@ -55,10 +53,13 @@ public class LegendarySorceryTest extends CardTestPlayerBase {
|
|||
// Flying, first strike, vigilance, trample, haste, protection from black and from red
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Akroma, Angel of Wrath", 1); // Legendary
|
||||
|
||||
// can't cast cause you don't have a legendary creature (only opponent have)
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Urza's Ruinous Blast");
|
||||
|
||||
//setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
//assertAllCommandsUsed();
|
||||
|
||||
assertGraveyardCount(playerA, "Urza's Ruinous Blast", 0);
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package org.mage.test.cards.single.cmr;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
|
||||
public class ArchelosLagoonMysticTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void test_Playable() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2 + 2); // add lands before Archelos, Lagoon Mystic to ignore ETB effects
|
||||
|
||||
// As long as Archelos, Lagoon Mystic is tapped, other permanents enter the battlefield tapped.
|
||||
// As long as Archelos, Lagoon Mystic is untapped, other permanents enter the battlefield untapped.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Archelos, Lagoon Mystic", 1);
|
||||
//
|
||||
addCard(Zone.HAND, playerA, "Grizzly Bears", 1); // {1}{G}
|
||||
addCard(Zone.HAND, playerA, "Deranged Outcast", 1); // {1}{G}
|
||||
|
||||
// first - untapped
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkPermanentTapped("untapped", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Archelos, Lagoon Mystic", false, 1);
|
||||
checkPermanentTapped("untapped", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", false, 1);
|
||||
|
||||
// prepare tapped mystic
|
||||
attack(1, playerA, "Archelos, Lagoon Mystic", playerB);
|
||||
checkPermanentTapped("tapped", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Archelos, Lagoon Mystic", true, 1);
|
||||
|
||||
// second - tapped
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Deranged Outcast");
|
||||
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
checkPermanentTapped("tapped", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Archelos, Lagoon Mystic", true, 1);
|
||||
checkPermanentTapped("tapped", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Deranged Outcast", true, 1);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package org.mage.test.cards.single.inv;
|
||||
|
||||
import mage.abilities.keyword.LandwalkAbility;
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.permanent.Permanent;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
|
||||
public class TravelersCloakTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void test_MustHaveLandWalkOfTheChosenType() {
|
||||
// Enchant creature
|
||||
// As Traveler's Cloak enters the battlefield, choose a land type.
|
||||
// When Traveler's Cloak enters the battlefield, draw a card.
|
||||
// Enchanted creature has landwalk of the chosen type.
|
||||
addCard(Zone.HAND, playerA, "Traveler's Cloak"); // {2}{U}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Kitesail Corsair", 1);
|
||||
|
||||
// cast and assign landwalk ability to creature
|
||||
checkAbility("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", LandwalkAbility.class, false);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Traveler's Cloak", "Grizzly Bears");
|
||||
setChoice(playerA, "Swamp"); // land type for landwalk
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkAbility("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", LandwalkAbility.class, true);
|
||||
|
||||
// check that it can't be blocked
|
||||
attack(1, playerA, "Grizzly Bears");
|
||||
runCode("check blocking", 1, PhaseStep.DECLARE_BLOCKERS, playerB, (info, player, game) -> {
|
||||
Permanent blocker = game.getBattlefield().getAllActivePermanents()
|
||||
.stream()
|
||||
.filter(p -> p.getName().equals("Kitesail Corsair"))
|
||||
.findFirst()
|
||||
.get();
|
||||
Assert.assertFalse("Grizzly Bears must be protected from blocking by Kitesail Corsair",
|
||||
game.getCombat().getGroups().get(0).canBlock(blocker, game));
|
||||
});
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
public class ConspicuousSnoopTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void testTopCardLibraryRevealed(){
|
||||
public void test_TopCardLibraryRevealed() {
|
||||
// Play with the top card of your library revealed.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Conspicuous Snoop");
|
||||
addCard(Zone.LIBRARY, playerA, "Swamp");
|
||||
|
@ -23,43 +23,49 @@ public class ConspicuousSnoopTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void castGoblinSpellsFromLibrary(){
|
||||
public void test_castGoblinSpellsFromLibrary() {
|
||||
skipInitShuffling();
|
||||
removeAllCardsFromLibrary(playerA);
|
||||
|
||||
// You may cast Goblin spells from the top of your library.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Conspicuous Snoop");
|
||||
|
||||
addCard(Zone.LIBRARY, playerA, "Goblin Lackey");
|
||||
skipInitShuffling();
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||
|
||||
// Whenever Goblin Lackey deals damage to a player, you may put a Goblin permanent card from your hand onto the battlefield.
|
||||
addCard(Zone.LIBRARY, playerA, "Atog", 1); // second from top
|
||||
addCard(Zone.LIBRARY, playerA, "Goblin Lackey", 1); // first from top
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2 * 2);
|
||||
|
||||
// Whenever Goblin Lackey deals damage to a player, you may put a Goblin permanent card from your hand onto the battlefield.
|
||||
checkPlayableAbility("can play goblin", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Goblin Lackey", true);
|
||||
checkPlayableAbility("can't play non goblin before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Atog", false);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin Lackey");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkPlayableAbility("can't play non goblin after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Atog", false);
|
||||
|
||||
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
assertAllCommandsUsed();
|
||||
assertPermanentCount(playerA, "Goblin Lackey", 1);
|
||||
|
||||
assertPermanentCount(playerA, "Goblin Lackey", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasActivatedAbilities(){
|
||||
public void test_hasActivatedAbilities() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
// Play with the top card of your library revealed.
|
||||
// You may cast Goblin spells from the top of your library.
|
||||
// As long as the top card of your library is a Goblin card, Conspicuous Snoop has all activated abilities of that card.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Conspicuous Snoop");
|
||||
// {R}: Goblin Balloon Brigade gains flying until end of turn.
|
||||
addCard(Zone.LIBRARY, playerA, "Goblin Balloon Brigade");
|
||||
addCard(Zone.LIBRARY, playerA, "Goblin Balloon Brigade");
|
||||
skipInitShuffling();
|
||||
|
||||
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
|
||||
assertAllCommandsUsed();
|
||||
assertAbilityCount(playerA, "Conspicuous Snoop", ActivatedAbility.class, 3); // (2 X casts + gains flying )
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,8 +79,6 @@ public class CastSplitCardsWithSpliceTest extends CardTestPlayerBase {
|
|||
addTarget(playerA, "Bow of Nylea"); // target right
|
||||
|
||||
// must used all mana
|
||||
//showAvaileableMana("after", 1, PhaseStep.POSTCOMBAT_MAIN, playerA);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
|
|
@ -1956,7 +1956,7 @@ public class TestPlayer implements Player {
|
|||
int index = 0;
|
||||
for (Map.Entry<String, String> entry : rEffects.entrySet()) {
|
||||
if (entry.getValue().startsWith(choice)) {
|
||||
choices.remove(choice);
|
||||
choices.remove(0);
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue