mirror of
https://github.com/correl/mage.git
synced 2024-12-26 03:00:11 +00:00
Merge origin/master
This commit is contained in:
commit
020beb1bf6
9 changed files with 882 additions and 304 deletions
|
@ -1633,7 +1633,42 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
|
||||
public static Deck buildDeck(List<Card> cardPool, final List<ColoredManaSymbol> colors) {
|
||||
return buildDeck(cardPool, colors, false);
|
||||
}
|
||||
|
||||
public static Deck buildDeck(List<Card> cardPool, final List<ColoredManaSymbol> colors, boolean onlyBasicLands) {
|
||||
if (onlyBasicLands) {
|
||||
return buildDeckWithOnlyBasicLands(cardPool);
|
||||
} else {
|
||||
return buildDeckWithNormalCards(cardPool, colors);
|
||||
}
|
||||
}
|
||||
|
||||
public static Deck buildDeckWithOnlyBasicLands(List<Card> cardPool) {
|
||||
// random cards from card pool
|
||||
Deck deck = new Deck();
|
||||
final int DECK_SIZE = 40;
|
||||
|
||||
List<Card> sortedCards = new ArrayList<>(cardPool);
|
||||
if (sortedCards.size() > 0) {
|
||||
while (deck.getCards().size() < DECK_SIZE) {
|
||||
deck.getCards().add(sortedCards.get(RandomUtil.nextInt(sortedCards.size())));
|
||||
}
|
||||
return deck;
|
||||
} else {
|
||||
addBasicLands(deck, "Forest", DECK_SIZE);
|
||||
return deck;
|
||||
}
|
||||
}
|
||||
|
||||
public static Deck buildDeckWithNormalCards(List<Card> cardPool, final List<ColoredManaSymbol> colors) {
|
||||
// top 23 cards plus basic lands until 40 deck size
|
||||
Deck deck = new Deck();
|
||||
final int DECK_SIZE = 40;
|
||||
final int DECK_CARDS_COUNT = 23;
|
||||
final int DECK_LANDS_COUNT = DECK_SIZE - DECK_CARDS_COUNT;
|
||||
|
||||
// sort card pool by top score
|
||||
List<Card> sortedCards = new ArrayList<>(cardPool);
|
||||
Collections.sort(sortedCards, new Comparator<Card>() {
|
||||
@Override
|
||||
|
@ -1643,8 +1678,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
return score2.compareTo(score1);
|
||||
}
|
||||
});
|
||||
|
||||
// get top cards
|
||||
int cardNum = 0;
|
||||
while (deck.getCards().size() < 23 && sortedCards.size() > cardNum) {
|
||||
while (deck.getCards().size() < DECK_CARDS_COUNT && sortedCards.size() > cardNum) {
|
||||
Card card = sortedCards.get(cardNum);
|
||||
if (!card.isBasic()) {
|
||||
deck.getCards().add(card);
|
||||
|
@ -1652,53 +1689,61 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
cardNum++;
|
||||
}
|
||||
// add basic lands
|
||||
|
||||
// add basic lands by color percent
|
||||
// TODO: compensate for non basic lands
|
||||
Mana mana = new Mana();
|
||||
for (Card card : deck.getCards()) {
|
||||
mana.add(card.getManaCost().getMana());
|
||||
}
|
||||
double total = mana.getBlack() + mana.getBlue() + mana.getGreen() + mana.getRed() + mana.getWhite();
|
||||
|
||||
// most frequent land is forest by defalt
|
||||
int mostLand = 0;
|
||||
String mostLandName = "Forest";
|
||||
if (mana.getGreen() > 0) {
|
||||
int number = (int) Math.round(mana.getGreen() / total * 17);
|
||||
int number = (int) Math.round(mana.getGreen() / total * DECK_LANDS_COUNT);
|
||||
addBasicLands(deck, "Forest", number);
|
||||
mostLand = number;
|
||||
}
|
||||
|
||||
if (mana.getBlack() > 0) {
|
||||
int number = (int) Math.round(mana.getBlack() / total * 17);
|
||||
int number = (int) Math.round(mana.getBlack() / total * DECK_LANDS_COUNT);
|
||||
addBasicLands(deck, "Swamp", number);
|
||||
if (number > mostLand) {
|
||||
mostLand = number;
|
||||
mostLandName = "Swamp";
|
||||
}
|
||||
}
|
||||
|
||||
if (mana.getBlue() > 0) {
|
||||
int number = (int) Math.round(mana.getBlue() / total * 17);
|
||||
int number = (int) Math.round(mana.getBlue() / total * DECK_LANDS_COUNT);
|
||||
addBasicLands(deck, "Island", number);
|
||||
if (number > mostLand) {
|
||||
mostLand = number;
|
||||
mostLandName = "Island";
|
||||
}
|
||||
}
|
||||
|
||||
if (mana.getWhite() > 0) {
|
||||
int number = (int) Math.round(mana.getWhite() / total * 17);
|
||||
int number = (int) Math.round(mana.getWhite() / total * DECK_LANDS_COUNT);
|
||||
addBasicLands(deck, "Plains", number);
|
||||
if (number > mostLand) {
|
||||
mostLand = number;
|
||||
mostLandName = "Plains";
|
||||
}
|
||||
}
|
||||
|
||||
if (mana.getRed() > 0) {
|
||||
int number = (int) Math.round(mana.getRed() / total * 17);
|
||||
int number = (int) Math.round(mana.getRed() / total * DECK_LANDS_COUNT);
|
||||
addBasicLands(deck, "Mountain", number);
|
||||
if (number > mostLand) {
|
||||
mostLandName = "Plains";
|
||||
}
|
||||
}
|
||||
|
||||
addBasicLands(deck, mostLandName, 40 - deck.getCards().size());
|
||||
// adds remaining lands (most popular name)
|
||||
addBasicLands(deck, mostLandName, DECK_SIZE - deck.getCards().size());
|
||||
|
||||
return deck;
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ import mage.target.common.TargetDefender;
|
|||
import mage.util.GameLog;
|
||||
import mage.util.ManaUtil;
|
||||
import mage.util.MessageToClient;
|
||||
import mage.util.RandomUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
|
@ -82,6 +83,7 @@ import org.apache.log4j.Logger;
|
|||
*/
|
||||
public class HumanPlayer extends PlayerImpl {
|
||||
|
||||
private transient Boolean responseOpenedForAnswer = false; // can't get response until prepared target (e.g. until send all fire events to all players)
|
||||
private final transient PlayerResponse response = new PlayerResponse();
|
||||
|
||||
protected static FilterCreatureForCombatBlock filterCreatureForCombatBlock = new FilterCreatureForCombatBlock();
|
||||
|
@ -148,6 +150,17 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|| (actionIterations > 0 && !actionQueueSaved.isEmpty()));
|
||||
}
|
||||
|
||||
protected void waitResponseOpen() {
|
||||
// wait response open for answer process
|
||||
while(!responseOpenedForAnswer && canRespond()) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
logger.warn("Response waiting interrapted for " + getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean pullResponseFromQueue(Game game) {
|
||||
if (actionQueue.isEmpty() && actionIterations > 0 && !actionQueueSaved.isEmpty()) {
|
||||
actionQueue = new LinkedList(actionQueueSaved);
|
||||
|
@ -164,6 +177,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_STACK_RESOLVED, game, null);
|
||||
}
|
||||
waitResponseOpen();
|
||||
synchronized (response) {
|
||||
response.copy(action);
|
||||
response.notifyAll();
|
||||
|
@ -174,6 +188,11 @@ public class HumanPlayer extends PlayerImpl {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected void prepareForResponse(Game game) {
|
||||
//logger.info("Prepare waiting " + getId());
|
||||
responseOpenedForAnswer = false;
|
||||
}
|
||||
|
||||
protected void waitForResponse(Game game) {
|
||||
if (isExecutingMacro()) {
|
||||
pullResponseFromQueue(game);
|
||||
|
@ -184,21 +203,27 @@ public class HumanPlayer extends PlayerImpl {
|
|||
// }
|
||||
return;
|
||||
}
|
||||
response.clear();
|
||||
logger.debug("Waiting response from player: " + getId());
|
||||
response.clear(); // TODO: only one response for all games (can play only one game per session)?!
|
||||
//logger.info("Waiting response from player: " + getId());
|
||||
game.resumeTimer(getTurnControlledBy());
|
||||
responseOpenedForAnswer = true; // start waiting for next response
|
||||
boolean loop = true;
|
||||
while (loop) {
|
||||
loop = false;
|
||||
|
||||
synchronized (response) {
|
||||
try {
|
||||
//logger.info("wait start: " + getId());
|
||||
response.wait();
|
||||
//logger.info("wait end: " + getId());
|
||||
} catch (InterruptedException ex) {
|
||||
logger.error("Response error for player " + getName() + " gameId: " + game.getId(), ex);
|
||||
} finally {
|
||||
responseOpenedForAnswer = false;
|
||||
game.pauseTimer(getTurnControlledBy());
|
||||
}
|
||||
}
|
||||
|
||||
if (response.getResponseConcedeCheck()) {
|
||||
((GameImpl) game).checkConcede();
|
||||
if (game.hasEnded()) {
|
||||
|
@ -210,6 +235,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
}
|
||||
}
|
||||
//logger.info("Waiting response DONE (res queue " + actionQueueSaved.size() + "): " + getId() + ", res: " + response.toString());
|
||||
if (recordingMacro && !macroTriggeredSelectionFlag) {
|
||||
// logger.info("Adding an action " + response);
|
||||
actionQueueSaved.add(new PlayerResponse(response));
|
||||
|
@ -227,6 +253,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
Map<String, Serializable> options = new HashMap<>();
|
||||
options.put("UI.left.btn.text", "Mulligan");
|
||||
options.put("UI.right.btn.text", "Keep");
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireAskPlayerEvent(playerId, new MessageToClient(message), null, options);
|
||||
}
|
||||
|
@ -269,6 +296,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
if (messageToClient.getSecondMessage() == null) {
|
||||
messageToClient.setSecondMessage(getRelatedObjectName(source, game));
|
||||
}
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireAskPlayerEvent(playerId, messageToClient, source, options);
|
||||
}
|
||||
|
@ -330,10 +358,11 @@ public class HumanPlayer extends PlayerImpl {
|
|||
replacementEffectChoice.setKeyChoices(rEffects);
|
||||
|
||||
while (!abort) {
|
||||
updateGameStatePriority("chooseEffect", game);
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireChooseChoiceEvent(playerId, replacementEffectChoice);
|
||||
}
|
||||
updateGameStatePriority("chooseEffect", game);
|
||||
waitForResponse(game);
|
||||
logger.debug("Choose effect: " + response.getString());
|
||||
if (response.getString() != null) {
|
||||
|
@ -367,6 +396,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
updateGameStatePriority("choose(3)", game);
|
||||
while (!abort) {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireChooseChoiceEvent(playerId, choice);
|
||||
}
|
||||
|
@ -416,6 +446,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
List<UUID> chosen = target.getTargets();
|
||||
options.put("chosen", (Serializable) chosen);
|
||||
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(), getRelatedObjectName(sourceId, game)), targetIds, required, getOptions(target, options));
|
||||
}
|
||||
|
@ -483,6 +514,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
required = false;
|
||||
}
|
||||
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(), getRelatedObjectName(source, game)), possibleTargets, required, getOptions(target, null));
|
||||
}
|
||||
|
@ -553,6 +585,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
options.put("choosable", (Serializable) choosable);
|
||||
}
|
||||
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage()), cards, required, options);
|
||||
}
|
||||
|
@ -617,6 +650,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
if (!isExecutingMacro()) {
|
||||
game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage(), getRelatedObjectName(source, game)), cards, required, options);
|
||||
}
|
||||
prepareForResponse(game);
|
||||
waitForResponse(game);
|
||||
if (response.getUUID() != null) {
|
||||
if (target.getTargets().contains(response.getUUID())) { // if already included remove it
|
||||
|
@ -643,6 +677,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) {
|
||||
updateGameStatePriority("chooseTargetAmount", game);
|
||||
while (!abort) {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage() + "\n Amount remaining:" + target.getAmountRemaining(), getRelatedObjectName(source, game)),
|
||||
target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game),
|
||||
|
@ -786,6 +821,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
while (canRespond()) {
|
||||
updateGameStatePriority("priority", game);
|
||||
holdingPriority = false;
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.firePriorityEvent(playerId);
|
||||
}
|
||||
|
@ -920,6 +956,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
macroTriggeredSelectionFlag = true;
|
||||
updateGameStatePriority("chooseTriggeredAbility", game);
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireSelectTargetTriggeredAbilityEvent(playerId, "Pick triggered ability (goes to the stack first)", abilitiesWithNoOrderSet);
|
||||
}
|
||||
|
@ -956,6 +993,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
protected boolean playManaHandling(Ability abilityToCast, ManaCost unpaid, String promptText, Game game) {
|
||||
updateGameStatePriority("playMana", game);
|
||||
Map<String, Serializable> options = new HashMap<>();
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.firePlayManaEvent(playerId, "Pay " + promptText, options);
|
||||
}
|
||||
|
@ -992,6 +1030,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
int xValue = 0;
|
||||
updateGameStatePriority("announceRepetitions", game);
|
||||
do {
|
||||
prepareForResponse(game);
|
||||
game.fireGetAmountEvent(playerId, "How many times do you want to repeat your shortcut?", 0, 999);
|
||||
waitForResponse(game);
|
||||
} while (response.getInteger() == null
|
||||
|
@ -1018,6 +1057,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
int xValue = 0;
|
||||
updateGameStatePriority("announceXMana", game);
|
||||
do {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireGetAmountEvent(playerId, message, min, max);
|
||||
}
|
||||
|
@ -1036,6 +1076,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
int xValue = 0;
|
||||
updateGameStatePriority("announceXCost", game);
|
||||
do {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireGetAmountEvent(playerId, message, min, max);
|
||||
}
|
||||
|
@ -1107,6 +1148,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
options.put(Constants.Option.SPECIAL_BUTTON, (Serializable) "All attack");
|
||||
}
|
||||
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireSelectEvent(playerId, "Select attackers", options);
|
||||
}
|
||||
|
@ -1326,6 +1368,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
return;
|
||||
}
|
||||
while (!abort) {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireSelectEvent(playerId, "Select blockers");
|
||||
}
|
||||
|
@ -1358,6 +1401,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
public UUID chooseAttackerOrder(List<Permanent> attackers, Game game) {
|
||||
updateGameStatePriority("chooseAttackerOrder", game);
|
||||
while (!abort) {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireSelectTargetEvent(playerId, "Pick attacker", attackers, true);
|
||||
}
|
||||
|
@ -1377,6 +1421,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
public UUID chooseBlockerOrder(List<Permanent> blockers, CombatGroup combatGroup, List<UUID> blockerOrder, Game game) {
|
||||
updateGameStatePriority("chooseBlockerOrder", game);
|
||||
while (!abort) {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireSelectTargetEvent(playerId, "Pick blocker", blockers, true);
|
||||
}
|
||||
|
@ -1395,6 +1440,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
protected void selectCombatGroup(UUID defenderId, UUID blockerId, Game game) {
|
||||
updateGameStatePriority("selectCombatGroup", game);
|
||||
TargetAttackingCreature target = new TargetAttackingCreature();
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireSelectTargetEvent(playerId, new MessageToClient("Select attacker to block", getRelatedObjectName(blockerId, game)),
|
||||
target.possibleTargets(null, playerId, game), false, getOptions(target, null));
|
||||
|
@ -1447,6 +1493,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
public int getAmount(int min, int max, String message, Game game) {
|
||||
updateGameStatePriority("getAmount", game);
|
||||
do {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireGetAmountEvent(playerId, message, min, max);
|
||||
}
|
||||
|
@ -1478,6 +1525,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
LinkedHashMap<UUID, SpecialAction> specialActions = game.getState().getSpecialActions().getControlledBy(playerId, false);
|
||||
if (!specialActions.isEmpty()) {
|
||||
updateGameStatePriority("specialAction", game);
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireGetChoiceEvent(playerId, name, null, new ArrayList<>(specialActions.values()));
|
||||
}
|
||||
|
@ -1494,6 +1542,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
LinkedHashMap<UUID, SpecialAction> specialActions = game.getState().getSpecialActions().getControlledBy(playerId, true);
|
||||
if (!specialActions.isEmpty()) {
|
||||
updateGameStatePriority("specialAction", game);
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireGetChoiceEvent(playerId, name, null, new ArrayList<>(specialActions.values()));
|
||||
}
|
||||
|
@ -1539,6 +1588,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
}
|
||||
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireGetChoiceEvent(playerId, name, object, new ArrayList<>(abilities.values()));
|
||||
}
|
||||
|
@ -1579,6 +1629,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
return (SpellAbility) useableAbilities.values().iterator().next();
|
||||
} else if (useableAbilities != null
|
||||
&& !useableAbilities.isEmpty()) {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireGetChoiceEvent(playerId, name, object, new ArrayList<>(useableAbilities.values()));
|
||||
}
|
||||
|
@ -1631,6 +1682,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
if (!modeMap.isEmpty()) {
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireGetModeEvent(playerId, "Choose Mode", modeMap);
|
||||
}
|
||||
|
@ -1660,6 +1712,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
public boolean choosePile(Outcome outcome, String message, List<? extends Card> pile1, List<? extends Card> pile2, Game game) {
|
||||
updateGameStatePriority("choosePile", game);
|
||||
do {
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
game.fireChoosePileEvent(playerId, message, pile1, pile2);
|
||||
}
|
||||
|
@ -1673,6 +1726,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
@Override
|
||||
public void setResponseString(String responseString) {
|
||||
waitResponseOpen();
|
||||
synchronized (response) {
|
||||
response.setString(responseString);
|
||||
response.notifyAll();
|
||||
|
@ -1682,6 +1736,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
@Override
|
||||
public void setResponseManaType(UUID manaTypePlayerId, ManaType manaType) {
|
||||
waitResponseOpen();
|
||||
synchronized (response) {
|
||||
response.setManaType(manaType);
|
||||
response.setResponseManaTypePlayerId(manaTypePlayerId);
|
||||
|
@ -1692,6 +1747,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
@Override
|
||||
public void setResponseUUID(UUID responseUUID) {
|
||||
waitResponseOpen();
|
||||
synchronized (response) {
|
||||
response.setUUID(responseUUID);
|
||||
response.notifyAll();
|
||||
|
@ -1701,15 +1757,17 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
@Override
|
||||
public void setResponseBoolean(Boolean responseBoolean) {
|
||||
waitResponseOpen();
|
||||
synchronized (response) {
|
||||
response.setBoolean(responseBoolean);
|
||||
response.notifyAll();
|
||||
logger.debug("Got response boolean from player: " + getId());
|
||||
logger.info("Got response boolean from player: " + getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponseInteger(Integer responseInteger) {
|
||||
waitResponseOpen();
|
||||
synchronized (response) {
|
||||
response.setInteger(responseInteger);
|
||||
response.notifyAll();
|
||||
|
@ -1720,6 +1778,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
@Override
|
||||
public void abort() {
|
||||
abort = true;
|
||||
waitResponseOpen();
|
||||
synchronized (response) {
|
||||
response.notifyAll();
|
||||
logger.debug("Got cancel action from player: " + getId());
|
||||
|
@ -1728,6 +1787,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
@Override
|
||||
public void signalPlayerConcede() {
|
||||
waitResponseOpen();
|
||||
synchronized (response) {
|
||||
response.setResponseConcedeCheck();
|
||||
response.notifyAll();
|
||||
|
@ -1737,6 +1797,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
@Override
|
||||
public void skip() {
|
||||
waitResponseOpen();
|
||||
synchronized (response) {
|
||||
response.setInteger(0);
|
||||
response.notifyAll();
|
||||
|
|
|
@ -1,28 +1,32 @@
|
|||
package org.mage.test.load;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.PlayerAction;
|
||||
import mage.interfaces.callback.CallbackClient;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.remote.Session;
|
||||
import mage.util.RandomUtil;
|
||||
import mage.utils.CompressUtil;
|
||||
import mage.view.GameClientMessage;
|
||||
import mage.view.GameView;
|
||||
import mage.view.SimpleCardView;
|
||||
import mage.view.TableClientMessage;
|
||||
import mage.view.*;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author noxx
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class LoadCallbackClient implements CallbackClient {
|
||||
|
||||
private static final Logger log = Logger.getLogger(LoadCallbackClient.class);
|
||||
//private static final Logger log = Logger.getLogger(LoadCallbackClient.class);
|
||||
private static final Logger log = Logger.getLogger("Load call");
|
||||
|
||||
private Session session;
|
||||
private UUID gameId;
|
||||
private UUID playerId;
|
||||
private boolean gameOver;
|
||||
private String gameResult = "unknown";
|
||||
private boolean needToConcede = false; // will concede on first priority
|
||||
|
||||
private volatile int controlCount;
|
||||
|
||||
|
@ -32,63 +36,152 @@ public class LoadCallbackClient implements CallbackClient {
|
|||
public void processCallback(ClientCallback callback) {
|
||||
//TODO
|
||||
controlCount = 0;
|
||||
log.info(callback.getMethod());
|
||||
callback.setData(CompressUtil.decompress(callback.getData()));
|
||||
|
||||
/*
|
||||
// random sleep can help with freezes (server concurrent access problem?!)
|
||||
try {
|
||||
Thread.sleep(RandomUtil.nextInt(1000));
|
||||
}catch (InterruptedException e) {
|
||||
log.error("thread error", e);
|
||||
}
|
||||
*/
|
||||
|
||||
log.info(callback.getMethod());
|
||||
log.info(getLogStartInfo() + "callback: " + callback.getMethod());
|
||||
|
||||
switch (callback.getMethod()) {
|
||||
|
||||
case START_GAME: {
|
||||
TableClientMessage message = (TableClientMessage) callback.getData();
|
||||
log.info(getLogStartInfo() + "game started");
|
||||
gameId = message.getGameId();
|
||||
playerId = message.getPlayerId();
|
||||
session.joinGame(message.getGameId());
|
||||
startControlThread();
|
||||
break;
|
||||
}
|
||||
case GAME_INFORM: {
|
||||
|
||||
case GAME_INFORM:
|
||||
case GAME_INFORM_PERSONAL: {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
log.info("Inform: " + message.getMessage());
|
||||
gameView = message.getGameView();
|
||||
log.info(getLogStartInfo() + "Inform: " + message.getMessage());
|
||||
break;
|
||||
}
|
||||
case GAME_INIT:
|
||||
break;
|
||||
|
||||
case GAME_TARGET: {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
this.gameView = message.getGameView();
|
||||
log.info("Target: " + message.getMessage());
|
||||
switch (message.getMessage()) {
|
||||
case "Select a starting player":
|
||||
session.sendPlayerUUID(gameId, playerId);
|
||||
break;
|
||||
return;
|
||||
//break;
|
||||
case "Select a card to discard":
|
||||
log.info("hand size: " + gameView.getHand().size());
|
||||
log.info(getLogStartInfo() + "hand size: " + gameView.getHand().size());
|
||||
SimpleCardView card = gameView.getHand().values().iterator().next();
|
||||
session.sendPlayerUUID(gameId, card.getId());
|
||||
break;
|
||||
return;
|
||||
//break;
|
||||
default:
|
||||
log.error(getLogStartInfo() + "unknown GAME_TARGET message: " + message.toString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GAME_ASK: {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
log.info("Ask: " + message.getMessage());
|
||||
if (message.getMessage().equals("Do you want to take a mulligan?")) {
|
||||
log.info(getLogStartInfo() + "Ask: " + message.getMessage());
|
||||
if (message.getMessage().startsWith("Mulligan")) {
|
||||
session.sendPlayerBoolean(gameId, false);
|
||||
return;
|
||||
} else {
|
||||
log.error(getLogStartInfo() + "unknown GAME_ASK message: " + message.toString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GAME_SELECT: {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
log.info("Select: " + message.getMessage());
|
||||
if (LoadPhaseManager.getInstance().isSkip(message.getGameView(), message.getMessage(), playerId)) {
|
||||
log.info("Skipped: " + message.getMessage());
|
||||
session.sendPlayerBoolean(gameId, false);
|
||||
this.gameView = message.getGameView();
|
||||
|
||||
// concede
|
||||
if (needToConcede) {
|
||||
log.info(getLogStartInfo() + "game conceded");
|
||||
needToConcede = false;
|
||||
session.sendPlayerAction(PlayerAction.CONCEDE, gameId, null);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
// end priority step
|
||||
session.sendPlayerBoolean(gameId, false);
|
||||
return;
|
||||
/*
|
||||
if (LoadPhaseManager.getInstance().isSkip(message.getGameView(), message.getMessage(), playerId)) {
|
||||
log.info(getLogStartInfo() + "Skipped: " + message.getMessage());
|
||||
session.sendPlayerBoolean(gameId, false);
|
||||
} else {
|
||||
log.error(getLogStartInfo() + "unknown GAME_SELECT or skips message: " + message.toString());
|
||||
}
|
||||
*/
|
||||
//break;
|
||||
}
|
||||
|
||||
case GAME_OVER:
|
||||
log.info("Game over");
|
||||
log.info(getLogStartInfo() + "Game over");
|
||||
gameOver = true;
|
||||
break;
|
||||
|
||||
case END_GAME_INFO:
|
||||
GameEndView message = (GameEndView) callback.getData();
|
||||
this.gameResult = message.hasWon() ? "win" : "lose";
|
||||
log.info(getLogStartInfo() + "Game end info, " + this.gameResult);
|
||||
break;
|
||||
|
||||
// skip callbacks (no need to react)
|
||||
case GAME_INIT:
|
||||
case GAME_UPDATE:
|
||||
case CHATMESSAGE:
|
||||
case JOINED_TABLE:
|
||||
break;
|
||||
|
||||
default:
|
||||
log.error(getLogStartInfo() + "Unknown callback: " + callback.getMethod() + ", " + callback.getData().toString());
|
||||
session.sendPlayerBoolean(gameId, false);
|
||||
return;
|
||||
//break;
|
||||
}
|
||||
}
|
||||
|
||||
private PlayerView getPlayer() {
|
||||
if ((this.gameView != null) && (this.playerId != null)) {
|
||||
for (PlayerView p: this.gameView.getPlayers()) {
|
||||
if (p.getPlayerId().equals(this.playerId)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getLogStartInfo() {
|
||||
String mes = "";
|
||||
|
||||
//throw new IllegalArgumentException("test exception");
|
||||
|
||||
if (this.session != null) {
|
||||
mes += session.getUserName() + ": ";
|
||||
}
|
||||
|
||||
PlayerView p = getPlayer();
|
||||
if (this.gameView != null && p != null && this.gameView.getStep() != null) {
|
||||
mes += "T" + this.gameView.getTurn() + "-" + this.gameView.getStep().getIndex() + ", L:" + p.getLibraryCount() + ", H:" + getPlayer().getHandCount() + ": ";
|
||||
}
|
||||
|
||||
return mes;
|
||||
}
|
||||
|
||||
public void setSession(Session session) {
|
||||
|
@ -108,8 +201,13 @@ public class LoadCallbackClient implements CallbackClient {
|
|||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if(isGameOver()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (controlCount > 5) {
|
||||
log.warn("Game seems freezed. Sending boolean message to server.");
|
||||
log.warn(getLogStartInfo() + "Game seems freezed. Sending boolean message to server.");
|
||||
session.sendPlayerBoolean(gameId, false);
|
||||
controlCount = 0;
|
||||
}
|
||||
|
@ -117,4 +215,12 @@ public class LoadCallbackClient implements CallbackClient {
|
|||
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void setConcede(boolean needToConcede) {
|
||||
this.needToConcede = needToConcede;
|
||||
}
|
||||
|
||||
public String getLastGameResult() {
|
||||
return this.gameResult;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
package org.mage.test.load;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.view.GameView;
|
||||
import mage.view.PlayerView;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class LoadPhaseManager {
|
||||
private static final Logger log = Logger.getLogger("Load phase");
|
||||
|
||||
private static final LoadPhaseManager instance = new LoadPhaseManager();
|
||||
|
||||
|
@ -31,52 +34,63 @@ public class LoadPhaseManager {
|
|||
public static String MAIN_2_OTHERS = "main2Others";
|
||||
public static String END_OF_TURN_OTHERS = "endOfTurnOthers";
|
||||
|
||||
private static Map<String, String> mapYou = new HashMap<String, String>() {{
|
||||
put("Upkeep - play instants and activated abilities.", UPKEEP_YOU);
|
||||
put("Draw - play instants and activated abilities.", DRAW_YOU);
|
||||
put("Precombat Main - play spells and abilities.", MAIN_YOU);
|
||||
put("Begin Combat - play instants and activated abilities.", BEFORE_COMBAT_YOU);
|
||||
put("End Combat - play instants and activated abilities.", END_OF_COMBAT_YOU);
|
||||
put("Postcombat Main - play spells and abilities.", MAIN_2_YOU);
|
||||
put("End Turn - play instants and activated abilities.", END_OF_TURN_YOU);
|
||||
}};
|
||||
private static Map<PhaseStep, Boolean> skipYou;
|
||||
static {
|
||||
skipYou = new HashMap() {{
|
||||
put(PhaseStep.UPKEEP, true);
|
||||
put(PhaseStep.PRECOMBAT_MAIN, true);
|
||||
put(PhaseStep.BEGIN_COMBAT, true);
|
||||
put(PhaseStep.DECLARE_ATTACKERS, true);
|
||||
put(PhaseStep.DECLARE_BLOCKERS, true);
|
||||
put(PhaseStep.END_COMBAT, true);
|
||||
put(PhaseStep.POSTCOMBAT_MAIN, true);
|
||||
put(PhaseStep.END_TURN, true);
|
||||
}};
|
||||
}
|
||||
|
||||
private static Map<String, String> mapOthers = new HashMap<String, String>() {{
|
||||
put("Upkeep - play instants and activated abilities.", UPKEEP_OTHERS);
|
||||
put("Draw - play instants and activated abilities.", DRAW_OTHERS);
|
||||
put("Precombat Main - play instants and activated abilities.", MAIN_OTHERS);
|
||||
put("Begin Combat - play instants and activated abilities.", BEFORE_COMBAT_OTHERS);
|
||||
put("End Combat - play instants and activated abilities.", END_OF_COMBAT_OTHERS);
|
||||
put("Postcombat Main - play instants and activated abilities.", MAIN_2_OTHERS);
|
||||
put("End Turn - play instants and activated abilities.", END_OF_TURN_OTHERS);
|
||||
}};
|
||||
private static Map<PhaseStep, Boolean> skipOthers;
|
||||
static {
|
||||
skipYou = new HashMap() {{
|
||||
put(PhaseStep.UPKEEP, true);
|
||||
put(PhaseStep.PRECOMBAT_MAIN, true);
|
||||
put(PhaseStep.BEGIN_COMBAT, true);
|
||||
put(PhaseStep.DECLARE_ATTACKERS, true);
|
||||
put(PhaseStep.DECLARE_BLOCKERS, true);
|
||||
put(PhaseStep.END_COMBAT, true);
|
||||
put(PhaseStep.POSTCOMBAT_MAIN, true);
|
||||
put(PhaseStep.END_TURN, true);
|
||||
}};
|
||||
}
|
||||
|
||||
public static LoadPhaseManager getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public boolean isSkip(GameView gameView, String message, UUID playerId) {
|
||||
// skip callbacks
|
||||
|
||||
UUID activePlayer = null;
|
||||
Map<String, String> map = mapOthers;
|
||||
Map<PhaseStep, Boolean> map = skipOthers;
|
||||
for (PlayerView playerView : gameView.getPlayers()) {
|
||||
if (playerView.isActive()) {
|
||||
activePlayer = playerView.getPlayerId();
|
||||
if (activePlayer.equals(playerId)) {
|
||||
map = mapYou;
|
||||
map = skipYou;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (activePlayer == null) {
|
||||
throw new IllegalStateException("No active player found.");
|
||||
}
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
if (message.equals(entry.getKey())) {
|
||||
/*if (message.equals("Precombat Main - play spells and abilities.")) {
|
||||
return false;
|
||||
}*/
|
||||
return true;
|
||||
}
|
||||
|
||||
// PROCCESS
|
||||
|
||||
if(map.containsKey(gameView.getStep())){
|
||||
return map.get(gameView.getStep());
|
||||
} else {
|
||||
log.error("Unknown phase manager step: " + gameView.getStep().toString());
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,26 +7,24 @@ import mage.cards.decks.DeckCardInfo;
|
|||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.cards.repository.CardInfo;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.constants.MatchTimeLimit;
|
||||
import mage.constants.MultiplayerAttackOption;
|
||||
import mage.constants.RangeOfInfluence;
|
||||
import mage.constants.*;
|
||||
import mage.game.match.MatchOptions;
|
||||
import mage.player.ai.ComputerPlayer;
|
||||
import mage.players.PlayerType;
|
||||
import mage.remote.Connection;
|
||||
import mage.remote.MageRemoteException;
|
||||
import mage.remote.Session;
|
||||
import mage.remote.SessionImpl;
|
||||
import mage.view.GameTypeView;
|
||||
import mage.view.TableView;
|
||||
import mage.util.RandomUtil;
|
||||
import mage.view.*;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Intended to test Mage server under different load patterns.
|
||||
|
@ -36,236 +34,296 @@ import java.util.UUID;
|
|||
*
|
||||
* Then it's also better to use -Xms256M -Xmx512M JVM options for these stests.
|
||||
*
|
||||
* @author noxx
|
||||
* @author JayDi85
|
||||
*/
|
||||
|
||||
public class LoadTest {
|
||||
|
||||
/**
|
||||
* Logger for tests
|
||||
*/
|
||||
private static final Logger log = Logger.getLogger(LoadTest.class);
|
||||
private static final Logger logger = Logger.getLogger(LoadTest.class);
|
||||
|
||||
/**
|
||||
* First player's username
|
||||
*/
|
||||
private static final String TEST_USER_NAME = "player";
|
||||
|
||||
/**
|
||||
* Second player's username
|
||||
*/
|
||||
private static final String TEST_USER_NAME_2 = "opponent";
|
||||
|
||||
/**
|
||||
* Server connection setting.
|
||||
*/
|
||||
private static final String TEST_SERVER = "localhost";
|
||||
|
||||
/**
|
||||
* Server connection setting.
|
||||
*/
|
||||
private static final int TEST_PORT = 17171;
|
||||
|
||||
/**
|
||||
* Server connection setting.
|
||||
*/
|
||||
private static final String TEST_PROXY_TYPE = "None";
|
||||
private static final String TEST_USER_NAME = "user";
|
||||
|
||||
/**
|
||||
* Determines how many times test will be executed in a row.
|
||||
*/
|
||||
private static final int EXECUTION_COUNT = 100;
|
||||
@Test
|
||||
public void test_CreateRandomDeck() {
|
||||
|
||||
/**
|
||||
* Determines how many times test will be executed in a row.
|
||||
*/
|
||||
private static final int EXECUTION_COUNT_PLAY_GAME = 100;
|
||||
Deck deck;
|
||||
|
||||
deck = generateRandomDeck("G", false);
|
||||
for(Card card : deck.getCards()) {
|
||||
Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in G",
|
||||
card.getColorIdentity().isGreen());
|
||||
}
|
||||
|
||||
deck = generateRandomDeck("U", false);
|
||||
for(Card card : deck.getCards()) {
|
||||
Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in U",
|
||||
card.getColorIdentity().isBlue());
|
||||
}
|
||||
|
||||
deck = generateRandomDeck("BR", false);
|
||||
for(Card card : deck.getCards()) {
|
||||
Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in BR",
|
||||
card.getColorIdentity().isBlack() || card.getColorIdentity().isRed());
|
||||
}
|
||||
|
||||
deck = generateRandomDeck("BUG", false);
|
||||
for(Card card : deck.getCards()) {
|
||||
Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in BUG",
|
||||
card.getColorIdentity().isBlack() || card.getColorIdentity().isBlue() || card.getColorIdentity().isGreen());
|
||||
}
|
||||
|
||||
// lands
|
||||
|
||||
deck = generateRandomDeck("UR", true);
|
||||
for(Card card : deck.getCards()) {
|
||||
Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in UR",
|
||||
card.getColorIdentity().isBlue() || card.getColorIdentity().isRed());
|
||||
Assert.assertEquals("card " + card.getName() + " must be basic land ", Rarity.LAND, card.getRarity());
|
||||
}
|
||||
|
||||
deck = generateRandomDeck("B", true);
|
||||
for(Card card : deck.getCards()) {
|
||||
Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in B", card.getColorIdentity().isBlack());
|
||||
Assert.assertEquals("card " + card.getName() + " must be basic land ", Rarity.LAND, card.getRarity());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests connecting with two players, creating game and starting it.
|
||||
*
|
||||
* Executes the test EXECUTION_COUNT times.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testStartGame() throws Exception {
|
||||
DeckCardLists deckList = createDeck();
|
||||
public void test_UsersConnectToServer() throws Exception {
|
||||
|
||||
for (int i = 0; i < EXECUTION_COUNT; i++) {
|
||||
Connection connection = createConnection(TEST_USER_NAME + i);
|
||||
// simple connection to server
|
||||
|
||||
SimpleMageClient mageClient = new SimpleMageClient();
|
||||
Session session = new SessionImpl(mageClient);
|
||||
// monitor other players
|
||||
LoadPlayer monitor = new LoadPlayer("monitor");
|
||||
Assert.assertTrue(monitor.session.isConnected());
|
||||
int startUsersCount = monitor.getAllRoomUsers().size();
|
||||
int minimumSleepTime = 2000;
|
||||
|
||||
session.connect(connection);
|
||||
UUID roomId = session.getMainRoomId();
|
||||
// user 1
|
||||
LoadPlayer player1 = new LoadPlayer("1");
|
||||
Thread.sleep(minimumSleepTime);
|
||||
Assert.assertEquals("Can't see users count change 1", startUsersCount + 1, monitor.getAllRoomUsers().size());
|
||||
Assert.assertNotNull("Can't find user 1", monitor.findUser(player1.userName));
|
||||
|
||||
GameTypeView gameTypeView = session.getGameTypes().get(0);
|
||||
log.info("Game type view: " + gameTypeView.getName());
|
||||
MatchOptions options = createGameOptions(gameTypeView, session);
|
||||
// user 2
|
||||
LoadPlayer player2 = new LoadPlayer("2");
|
||||
Thread.sleep(minimumSleepTime);
|
||||
Assert.assertEquals("Can't see users count change 2", startUsersCount + 2, monitor.getAllRoomUsers().size());
|
||||
Assert.assertNotNull("Can't find user 2", monitor.findUser(player2.userName));
|
||||
}
|
||||
|
||||
TableView table = session.createTable(roomId, options);
|
||||
@Test
|
||||
@Ignore
|
||||
public void test_TwoUsersPlayGameUntilEnd() {
|
||||
// simple connection to server test
|
||||
|
||||
if (!session.joinTable(roomId, table.getTableId(), TEST_USER_NAME + i, PlayerType.HUMAN, 1, deckList,"")) {
|
||||
log.error("Error while joining table");
|
||||
Assert.fail("Error while joining table");
|
||||
return;
|
||||
// monitor other players
|
||||
LoadPlayer monitor = new LoadPlayer("monitor");
|
||||
|
||||
// users
|
||||
LoadPlayer player1 = new LoadPlayer("1");
|
||||
LoadPlayer player2 = new LoadPlayer("2");
|
||||
|
||||
// game by user 1
|
||||
GameTypeView gameType = player1.session.getGameTypes().get(0);
|
||||
MatchOptions gameOptions = createSimpleGameOptions(gameType, player1.session);
|
||||
TableView game = player1.session.createTable(player1.roomID, gameOptions);
|
||||
UUID tableId = game.getTableId();
|
||||
Assert.assertEquals(player1.userName, game.getControllerName());
|
||||
|
||||
DeckCardLists deckList = createSimpleDeck("GR", true);
|
||||
Optional<TableView> checkGame;
|
||||
|
||||
/*
|
||||
for(DeckCardInfo info: deckList.getCards()) {
|
||||
logger.info(info.getCardName());
|
||||
}*/
|
||||
|
||||
// before connect
|
||||
checkGame = monitor.getTable(tableId);
|
||||
Assert.assertTrue(checkGame.isPresent());
|
||||
Assert.assertEquals(2, checkGame.get().getSeats().size());
|
||||
Assert.assertEquals("", checkGame.get().getSeats().get(0).getPlayerName());
|
||||
Assert.assertEquals("", checkGame.get().getSeats().get(1).getPlayerName());
|
||||
|
||||
// connect user 1
|
||||
Assert.assertTrue(player1.session.joinTable(player1.roomID, tableId, player1.userName, PlayerType.HUMAN, 1, deckList, ""));
|
||||
checkGame = monitor.getTable(tableId);
|
||||
Assert.assertTrue(checkGame.isPresent());
|
||||
Assert.assertEquals(2, checkGame.get().getSeats().size());
|
||||
Assert.assertEquals(player1.userName, checkGame.get().getSeats().get(0).getPlayerName());
|
||||
Assert.assertEquals("", checkGame.get().getSeats().get(1).getPlayerName());
|
||||
|
||||
// connect user 2
|
||||
Assert.assertTrue(player2.session.joinTable(player2.roomID, tableId, player2.userName, PlayerType.HUMAN, 1, deckList, ""));
|
||||
checkGame = monitor.getTable(tableId);
|
||||
Assert.assertTrue(checkGame.isPresent());
|
||||
Assert.assertEquals(2, checkGame.get().getSeats().size());
|
||||
Assert.assertEquals(player1.userName, checkGame.get().getSeats().get(0).getPlayerName());
|
||||
Assert.assertEquals(player2.userName, checkGame.get().getSeats().get(1).getPlayerName());
|
||||
|
||||
// match start
|
||||
Assert.assertTrue(player1.session.startMatch(player1.roomID, tableId));
|
||||
|
||||
// playing until game over
|
||||
while(!player1.client.isGameOver() && !player2.client.isGameOver()) {
|
||||
checkGame = monitor.getTable(tableId);
|
||||
logger.warn(checkGame.get().getTableState());
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e){
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void test_GameThread() {
|
||||
// simple game thread to the end
|
||||
|
||||
LoadGame game = new LoadGame(
|
||||
"game",
|
||||
"thread",
|
||||
createSimpleDeck("GR", true),
|
||||
createSimpleDeck("GR", true)
|
||||
);
|
||||
game.gameStart();
|
||||
|
||||
while (game.isPlaying()) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertEquals("finished", game.gameResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void test_GameThreadWithAbort() {
|
||||
// simple game thread with game abort
|
||||
|
||||
LoadGame game = new LoadGame(
|
||||
"game",
|
||||
"thread",
|
||||
createSimpleDeck("GR", true),
|
||||
createSimpleDeck("GR", true)
|
||||
);
|
||||
game.gameStart();
|
||||
game.gameEnd(true); // abort -- close client thread
|
||||
Assert.assertEquals("aborted", game.gameResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void test_GameThreadWithConcede() {
|
||||
// simple game thread with game abort
|
||||
|
||||
LoadGame game = new LoadGame(
|
||||
"game",
|
||||
"thread",
|
||||
createSimpleDeck("GR", true),
|
||||
createSimpleDeck("GR", true)
|
||||
);
|
||||
game.gameStart();
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (Throwable e) {
|
||||
//
|
||||
}
|
||||
game.gameConcede(1);
|
||||
game.gameWaitToStop();
|
||||
Assert.assertEquals("finished", game.gameResult);
|
||||
Assert.assertEquals("lose", game.player1.lastGameResult);
|
||||
Assert.assertEquals("win", game.player2.lastGameResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void test_MultipleGames() {
|
||||
// multiple games until finish
|
||||
|
||||
Instant startTime = Instant.now();
|
||||
|
||||
int MAX_GAMES = 30;
|
||||
|
||||
// creating
|
||||
logger.info("creating games...");
|
||||
ArrayList<LoadGame> gamesList = new ArrayList<>();
|
||||
for(int i = 1; i <= MAX_GAMES; i++) {
|
||||
gamesList.add(new LoadGame(
|
||||
"game" + i,
|
||||
"game" + i,
|
||||
createSimpleDeck("GR", true),
|
||||
createSimpleDeck("GR", true)
|
||||
));
|
||||
}
|
||||
logger.info("created " + gamesList.size() + " games");
|
||||
|
||||
// running
|
||||
for(LoadGame game: gamesList) {
|
||||
game.gameStart();
|
||||
}
|
||||
logger.info("run " + gamesList.size() + " games");
|
||||
|
||||
// waiting
|
||||
while (true) {
|
||||
boolean isComplete = true;
|
||||
for(LoadGame game: gamesList) {
|
||||
isComplete = isComplete && !game.isPlaying();
|
||||
}
|
||||
|
||||
/*** Connect with a second player ***/
|
||||
Connection connection2 = createConnection(TEST_USER_NAME_2 + i);
|
||||
SimpleMageClient mageClient2 = new SimpleMageClient();
|
||||
Session session2 = new SessionImpl(mageClient2);
|
||||
session2.connect(connection2);
|
||||
UUID roomId2 = session2.getMainRoomId();
|
||||
|
||||
// connect to the table with the same deck
|
||||
if (!session2.joinTable(roomId2, table.getTableId(), TEST_USER_NAME_2 + i, PlayerType.HUMAN, 1, deckList,"")) {
|
||||
log.error("Error while joining table");
|
||||
Assert.fail("Error while joining table");
|
||||
return;
|
||||
if(isComplete) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*** Start game ***/
|
||||
session.startMatch(roomId, table.getTableId());
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
logger.info("completed " + gamesList.size() + " games");
|
||||
|
||||
Thread.sleep(100);
|
||||
Instant endTime = Instant.now();
|
||||
logger.info("total time: " + ChronoUnit.SECONDS.between(startTime, endTime) + " secs");
|
||||
|
||||
// check statuses
|
||||
ArrayList<String> errors = new ArrayList<>();
|
||||
for(LoadGame game: gamesList) {
|
||||
if (!"finished".equals(game.gameResult)) {
|
||||
errors.add(game.gameName + ": not finished, got " + game.gameResult);
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.size() > 0) {
|
||||
System.out.println("Not all games finished, founded " + errors.size() + " errors: ");
|
||||
for (String s: errors) {
|
||||
System.out.println(s);
|
||||
}
|
||||
Assert.fail("Not all games finished");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests 10 simple games played one after another.
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSimpleGame() throws Exception {
|
||||
final DeckCardLists deckList = createDeck();
|
||||
|
||||
for (int i = 0; i < EXECUTION_COUNT_PLAY_GAME; i++) {
|
||||
final int j = i;
|
||||
Thread t = new Thread(() -> {
|
||||
try {
|
||||
testSimpleGame0(deckList, j);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests simple game till the end (game over).
|
||||
* Players do nothing but skip phases and discard cards at the end.
|
||||
*
|
||||
* This results in a game that lasts until there is no cards in library.
|
||||
*/
|
||||
private boolean testSimpleGame0(DeckCardLists deckList, int i) throws InterruptedException {
|
||||
Connection connection = createConnection(TEST_USER_NAME + i);
|
||||
|
||||
SimpleMageClient mageClient = new SimpleMageClient();
|
||||
Session session = new SessionImpl(mageClient);
|
||||
|
||||
session.connect(connection);
|
||||
|
||||
mageClient.setSession(session);
|
||||
UUID roomId = session.getMainRoomId();
|
||||
|
||||
GameTypeView gameTypeView = session.getGameTypes().get(0);
|
||||
log.info("Game type view: " + gameTypeView.getName());
|
||||
MatchOptions options = createGameOptions(gameTypeView, session);
|
||||
|
||||
TableView table = session.createTable(roomId, options);
|
||||
|
||||
if (!session.joinTable(roomId, table.getTableId(), TEST_USER_NAME + i, PlayerType.HUMAN, 1, deckList,"")) {
|
||||
log.error("Error while joining table");
|
||||
Assert.fail("Error while joining table");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*** Connect with a second player ***/
|
||||
Connection connection2 = createConnection(TEST_USER_NAME_2 + i);
|
||||
SimpleMageClient mageClient2 = new SimpleMageClient();
|
||||
Session session2 = new SessionImpl(mageClient2);
|
||||
session2.connect(connection2);
|
||||
|
||||
mageClient2.setSession(session2);
|
||||
UUID roomId2 = session2.getMainRoomId();
|
||||
|
||||
// connect to the table with the same deck
|
||||
if (!session2.joinTable(roomId2, table.getTableId(), TEST_USER_NAME_2 + i, PlayerType.HUMAN, 1, deckList,"")) {
|
||||
log.error("Error while joining table");
|
||||
Assert.fail("Error while joining table");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*** Start game ***/
|
||||
session.startMatch(roomId, table.getTableId());
|
||||
|
||||
while (!mageClient.isGameOver()) {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests playing the whole game.
|
||||
* Player use cheat to add lands, creatures and other cards.
|
||||
* Then play only lands, one of them plays 1 damage targeting player.
|
||||
*
|
||||
* This results in 40 turns of the game.
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testPlayGame() throws Exception {
|
||||
//TODO: to be implemented
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates connection to the server.
|
||||
* Server should run independently.
|
||||
*
|
||||
* @param username
|
||||
* @return
|
||||
*/
|
||||
private Connection createConnection(String username) {
|
||||
Connection connection = new Connection();
|
||||
connection.setUsername(username);
|
||||
connection.setHost(TEST_SERVER);
|
||||
connection.setPort(TEST_PORT);
|
||||
private Connection createSimpleConnection(String username) {
|
||||
Connection con = new Connection();
|
||||
con.setUsername(username);
|
||||
con.setHost(TEST_SERVER);
|
||||
con.setPort(TEST_PORT);
|
||||
Connection.ProxyType proxyType = Connection.ProxyType.valueByText(TEST_PROXY_TYPE);
|
||||
connection.setProxyType(proxyType);
|
||||
return connection;
|
||||
con.setProxyType(proxyType);
|
||||
return con;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns random deck.
|
||||
* Converts deck returned by {@link #generateRandomDeck} method to {@link DeckCardLists} format.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private DeckCardLists createDeck() {
|
||||
DeckCardLists deckList = new DeckCardLists();
|
||||
Deck deck = generateRandomDeck();
|
||||
for (Card card : deck.getCards()) {
|
||||
CardInfo cardInfo = CardRepository.instance.findCard(card.getExpansionSetCode(), card.getCardNumber());
|
||||
if (cardInfo != null) {
|
||||
deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode()));
|
||||
}
|
||||
}
|
||||
return deckList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates game options with two human players.
|
||||
*
|
||||
* @param gameTypeView
|
||||
* @param session
|
||||
* @return
|
||||
*/
|
||||
private MatchOptions createGameOptions(GameTypeView gameTypeView, Session session) {
|
||||
private MatchOptions createSimpleGameOptions(GameTypeView gameTypeView, Session session) {
|
||||
MatchOptions options = new MatchOptions("Test game", gameTypeView.getName(), false, 2);
|
||||
|
||||
options.getPlayerTypes().add(PlayerType.HUMAN);
|
||||
|
@ -280,21 +338,224 @@ public class LoadTest {
|
|||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates random deck in {@link Deck} format.
|
||||
* Uses {B}{R} as deck colors.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Deck generateRandomDeck() {
|
||||
String selectedColors = "BR";
|
||||
private Deck generateRandomDeck(String colors, boolean onlyBasicLands) {
|
||||
logger.info("Building " + (onlyBasicLands ? "only lands" : "random") + " deck with colors: " + colors);
|
||||
|
||||
List<ColoredManaSymbol> allowedColors = new ArrayList<>();
|
||||
log.info("Building deck with colors: " + selectedColors);
|
||||
for (int i = 0; i < selectedColors.length(); i++) {
|
||||
char c = selectedColors.charAt(i);
|
||||
for (int i = 0; i < colors.length(); i++) {
|
||||
char c = colors.charAt(i);
|
||||
allowedColors.add(ColoredManaSymbol.lookup(c));
|
||||
}
|
||||
List<Card> cardPool = Sets.generateRandomCardPool(45, allowedColors);
|
||||
return ComputerPlayer.buildDeck(cardPool, allowedColors);
|
||||
List<Card> cardPool = Sets.generateRandomCardPool(45, allowedColors, onlyBasicLands);
|
||||
return ComputerPlayer.buildDeck(cardPool, allowedColors, onlyBasicLands);
|
||||
}
|
||||
|
||||
private DeckCardLists createSimpleDeck(String colors, boolean onlyBasicLands) {
|
||||
Deck deck = generateRandomDeck(colors, onlyBasicLands);
|
||||
|
||||
DeckCardLists deckList = new DeckCardLists();
|
||||
for (Card card : deck.getCards()) {
|
||||
CardInfo cardInfo = CardRepository.instance.findCard(card.getExpansionSetCode(), card.getCardNumber());
|
||||
if (cardInfo != null) {
|
||||
deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode()));
|
||||
}
|
||||
}
|
||||
return deckList;
|
||||
}
|
||||
|
||||
private class LoadPlayer {
|
||||
String userName;
|
||||
Connection connection;
|
||||
SimpleMageClient client;
|
||||
Session session;
|
||||
UUID roomID;
|
||||
UUID createdTableID;
|
||||
UUID connectedTableID;
|
||||
DeckCardLists deckList;
|
||||
String lastGameResult = "";
|
||||
|
||||
public LoadPlayer(String userPrefix) {
|
||||
this.userName = TEST_USER_NAME + "_" + userPrefix + "_" + RandomUtil.nextInt(10000);
|
||||
this.connection = createSimpleConnection(this.userName);
|
||||
this.client = new SimpleMageClient();
|
||||
this.session = new SessionImpl(this.client);
|
||||
|
||||
this.session.connect(this.connection);
|
||||
this.client.setSession(this.session);
|
||||
this.roomID = this.session.getMainRoomId();
|
||||
}
|
||||
|
||||
public ArrayList<UsersView> getAllRoomUsers() {
|
||||
ArrayList<UsersView> res = new ArrayList<>();
|
||||
try {
|
||||
for (RoomUsersView roomUsers : this.session.getRoomUsers(this.roomID)) {
|
||||
res.addAll(roomUsers.getUsersView());
|
||||
}
|
||||
} catch (MageRemoteException e)
|
||||
{
|
||||
logger.error(e);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public UsersView findUser(String userName) {
|
||||
for (UsersView user: this.getAllRoomUsers()) {
|
||||
if (user.getUserName().equals(userName)) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Optional<TableView> getTable(UUID tableID) {
|
||||
return this.session.getTable(this.roomID, tableID);
|
||||
}
|
||||
|
||||
public UUID createNewTable() {
|
||||
GameTypeView gameType = this.session.getGameTypes().get(0);
|
||||
MatchOptions gameOptions = createSimpleGameOptions(gameType, this.session);
|
||||
TableView game = this.session.createTable(this.roomID, gameOptions);
|
||||
this.createdTableID = game.getTableId();
|
||||
Assert.assertEquals(this.userName, game.getControllerName());
|
||||
|
||||
connectToTable(this.createdTableID);
|
||||
|
||||
return this.createdTableID;
|
||||
}
|
||||
|
||||
public void connectToTable(UUID tableID) {
|
||||
Assert.assertTrue(this.session.joinTable(this.roomID, tableID, this.userName, PlayerType.HUMAN, 1, this.deckList, ""));
|
||||
this.connectedTableID = tableID;
|
||||
}
|
||||
|
||||
public void startMatch() {
|
||||
Assert.assertNotNull(this.createdTableID);
|
||||
Assert.assertTrue(this.session.startMatch(this.roomID, this.createdTableID));
|
||||
}
|
||||
|
||||
public void setDeckList(DeckCardLists deckList) {
|
||||
this.deckList = deckList;
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
this.session.disconnect(false);
|
||||
}
|
||||
|
||||
public void concede() {
|
||||
this.client.setConcede(true);
|
||||
}
|
||||
}
|
||||
|
||||
private class LoadGame {
|
||||
String gameName = null;
|
||||
Thread runningThread = null;
|
||||
LoadPlayer player1 = null;
|
||||
LoadPlayer player2 = null;
|
||||
Boolean abort = false;
|
||||
UUID tableID = null;
|
||||
String gameResult = null;
|
||||
|
||||
public LoadGame(String gameName, String playerPrefix) {
|
||||
this(gameName, playerPrefix,
|
||||
createSimpleDeck("GR", true),
|
||||
createSimpleDeck("GR", true)
|
||||
);
|
||||
}
|
||||
|
||||
public LoadGame(String gameName, String playerPrefix, DeckCardLists deck1, DeckCardLists deck2) {
|
||||
this.gameName = gameName;
|
||||
|
||||
player1 = new LoadPlayer(playerPrefix + "_" + 1);
|
||||
player1.setDeckList(deck1);
|
||||
|
||||
player2 = new LoadPlayer(playerPrefix + "_" + 2);
|
||||
player2.setDeckList(deck2);
|
||||
}
|
||||
|
||||
public void gameStart() {
|
||||
|
||||
this.abort = false;
|
||||
|
||||
runningThread = new Thread(() -> {
|
||||
try {
|
||||
this.tableID = this.player1.createNewTable();
|
||||
Assert.assertNotNull(this.tableID);
|
||||
this.player2.connectToTable(this.tableID);
|
||||
this.gameResult = "prepared";
|
||||
|
||||
this.player1.startMatch();
|
||||
this.gameResult = "started";
|
||||
|
||||
// playing until game over or abort
|
||||
while(!abort && (!player1.client.isGameOver() || !player2.client.isGameOver())) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e){
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// game results
|
||||
if (abort) {
|
||||
this.gameResult = "aborted";
|
||||
} else {
|
||||
this.gameResult = "finished";
|
||||
}
|
||||
player1.lastGameResult = player1.client.getLastGameResult();
|
||||
player2.lastGameResult = player2.client.getLastGameResult();
|
||||
} catch (Throwable e) {
|
||||
this.gameResult = "error";
|
||||
logger.fatal("Game thread " + this.gameName + " was stopped by error");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// disconnect on end
|
||||
this.player1.disconnect();
|
||||
this.player2.disconnect();
|
||||
|
||||
// clean up after game
|
||||
this.runningThread = null;
|
||||
this.tableID = null;
|
||||
});
|
||||
|
||||
runningThread.start();
|
||||
}
|
||||
|
||||
public void gameEnd() {
|
||||
gameEnd(false);
|
||||
}
|
||||
|
||||
public void gameEnd(Boolean waitToStop) {
|
||||
this.abort = true;
|
||||
|
||||
if (waitToStop) {
|
||||
gameWaitToStop();
|
||||
}
|
||||
}
|
||||
|
||||
public void gameConcede(int playerNumber) {
|
||||
switch (playerNumber) {
|
||||
case 1:
|
||||
this.player1.concede();
|
||||
break;
|
||||
case 2:
|
||||
this.player2.concede();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void gameWaitToStop() {
|
||||
while (this.runningThread != null) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean isPlaying() {
|
||||
return (this.runningThread != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import org.apache.log4j.Logger;
|
|||
/**
|
||||
* For tests only
|
||||
*
|
||||
* @author noxx
|
||||
* @author noxx, JayDi85
|
||||
*/
|
||||
public class SimpleMageClient implements MageClient {
|
||||
|
||||
|
@ -20,7 +20,7 @@ public class SimpleMageClient implements MageClient {
|
|||
|
||||
private static final Logger log = Logger.getLogger(SimpleMageClient.class);
|
||||
|
||||
private final CallbackClient callbackClient;
|
||||
private final LoadCallbackClient callbackClient;
|
||||
|
||||
public SimpleMageClient() {
|
||||
clientId = UUID.randomUUID();
|
||||
|
@ -54,7 +54,11 @@ public class SimpleMageClient implements MageClient {
|
|||
|
||||
@Override
|
||||
public void processCallback(ClientCallback callback) {
|
||||
callbackClient.processCallback(callback);
|
||||
try {
|
||||
callbackClient.processCallback(callback);
|
||||
} catch (Throwable e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSession(Session session) {
|
||||
|
@ -64,4 +68,12 @@ public class SimpleMageClient implements MageClient {
|
|||
public boolean isGameOver() {
|
||||
return ((LoadCallbackClient)callbackClient).isGameOver();
|
||||
}
|
||||
|
||||
public void setConcede(boolean needToConcede) {
|
||||
this.callbackClient.setConcede(needToConcede);
|
||||
}
|
||||
|
||||
public String getLastGameResult() {
|
||||
return this.callbackClient.getLastGameResult();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,12 +111,14 @@ public class ContinuousEffects implements Serializable {
|
|||
|
||||
costModificationEffects = effect.costModificationEffects.copy();
|
||||
spliceCardEffects = effect.spliceCardEffects.copy();
|
||||
temporaryEffects.putAll(effect.temporaryEffects);
|
||||
for (Map.Entry<ContinuousEffect, Set<Ability>> entry: effect.temporaryEffects.entrySet()) {
|
||||
temporaryEffects.put(entry.getKey().copy(), entry.getValue());
|
||||
}
|
||||
collectAllEffects();
|
||||
order = effect.order;
|
||||
}
|
||||
|
||||
private void collectAllEffects() {
|
||||
private synchronized void collectAllEffects() {
|
||||
allEffectsLists.add(layeredEffects);
|
||||
allEffectsLists.add(continuousRuleModifyingEffects);
|
||||
allEffectsLists.add(replacementEffects);
|
||||
|
@ -143,7 +145,7 @@ public class ContinuousEffects implements Serializable {
|
|||
return restrictionEffects;
|
||||
}
|
||||
|
||||
public void removeEndOfCombatEffects() {
|
||||
public synchronized void removeEndOfCombatEffects() {
|
||||
layeredEffects.removeEndOfCombatEffects();
|
||||
continuousRuleModifyingEffects.removeEndOfCombatEffects();
|
||||
replacementEffects.removeEndOfCombatEffects();
|
||||
|
@ -157,7 +159,7 @@ public class ContinuousEffects implements Serializable {
|
|||
spliceCardEffects.removeEndOfCombatEffects();
|
||||
}
|
||||
|
||||
public void removeEndOfTurnEffects() {
|
||||
public synchronized void removeEndOfTurnEffects() {
|
||||
layeredEffects.removeEndOfTurnEffects();
|
||||
continuousRuleModifyingEffects.removeEndOfTurnEffects();
|
||||
replacementEffects.removeEndOfTurnEffects();
|
||||
|
@ -171,7 +173,7 @@ public class ContinuousEffects implements Serializable {
|
|||
spliceCardEffects.removeEndOfTurnEffects();
|
||||
}
|
||||
|
||||
public void removeInactiveEffects(Game game) {
|
||||
public synchronized void removeInactiveEffects(Game game) {
|
||||
layeredEffects.removeInactiveEffects(game);
|
||||
continuousRuleModifyingEffects.removeInactiveEffects(game);
|
||||
replacementEffects.removeInactiveEffects(game);
|
||||
|
@ -186,7 +188,7 @@ public class ContinuousEffects implements Serializable {
|
|||
spliceCardEffects.removeInactiveEffects(game);
|
||||
}
|
||||
|
||||
public List<ContinuousEffect> getLayeredEffects(Game game) {
|
||||
public synchronized List<ContinuousEffect> getLayeredEffects(Game game) {
|
||||
List<ContinuousEffect> layerEffects = new ArrayList<>();
|
||||
for (ContinuousEffect effect : layeredEffects) {
|
||||
switch (effect.getDuration()) {
|
||||
|
@ -226,7 +228,7 @@ public class ContinuousEffects implements Serializable {
|
|||
*
|
||||
* @param layerEffects
|
||||
*/
|
||||
private void updateTimestamps(List<ContinuousEffect> layerEffects) {
|
||||
private synchronized void updateTimestamps(List<ContinuousEffect> layerEffects) {
|
||||
for (ContinuousEffect continuousEffect : layerEffects) {
|
||||
// check if it's new, then set order
|
||||
if (!previous.contains(continuousEffect)) {
|
||||
|
@ -857,7 +859,7 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
|
||||
//20091005 - 613
|
||||
public void apply(Game game) {
|
||||
public synchronized void apply(Game game) {
|
||||
removeInactiveEffects(game);
|
||||
List<ContinuousEffect> activeLayerEffects = getLayeredEffects(game);
|
||||
|
||||
|
@ -1071,7 +1073,7 @@ public class ContinuousEffects implements Serializable {
|
|||
* @param sourceId
|
||||
* @param source
|
||||
*/
|
||||
public void addEffect(ContinuousEffect effect, UUID sourceId, Ability source) {
|
||||
public synchronized void addEffect(ContinuousEffect effect, UUID sourceId, Ability source) {
|
||||
if (!(source instanceof MageSingleton)) { // because MageSingletons may never be removed by removing the temporary effecs they are not added to the temporaryEffects to prevent this
|
||||
effect.setTemporary(true);
|
||||
Set<Ability> abilities = temporaryEffects.get(effect);
|
||||
|
@ -1089,7 +1091,7 @@ public class ContinuousEffects implements Serializable {
|
|||
addEffect(effect, source);
|
||||
}
|
||||
|
||||
public void addEffect(ContinuousEffect effect, Ability source) {
|
||||
public synchronized void addEffect(ContinuousEffect effect, Ability source) {
|
||||
if (effect == null) {
|
||||
logger.error("Effect is null: " + source.toString());
|
||||
return;
|
||||
|
@ -1167,14 +1169,14 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
public synchronized void clear() {
|
||||
for (ContinuousEffectsList effectsList : allEffectsLists) {
|
||||
effectsList.clear();
|
||||
}
|
||||
temporaryEffects.clear();
|
||||
}
|
||||
|
||||
public void removeAllTemporaryEffects() {
|
||||
public synchronized void removeAllTemporaryEffects() {
|
||||
for (Map.Entry<ContinuousEffect, Set<Ability>> entry : temporaryEffects.entrySet()) {
|
||||
switch (entry.getKey().getEffectType()) {
|
||||
case REPLACEMENT:
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.cards;
|
||||
|
||||
import mage.Mana;
|
||||
import mage.cards.decks.DeckCardInfo;
|
||||
import mage.cards.decks.DeckCardLayout;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
|
@ -35,9 +36,12 @@ import mage.cards.repository.CardInfo;
|
|||
import mage.cards.repository.CardRepository;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.constants.Rarity;
|
||||
import mage.filter.FilterMana;
|
||||
import mage.util.ClassScanner;
|
||||
import mage.util.RandomUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.PrintWriter;
|
||||
|
@ -45,7 +49,7 @@ import java.util.*;
|
|||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
* @author BetaSteward_at_googlemail.com, JayDi85
|
||||
*/
|
||||
public class Sets extends HashMap<String, ExpansionSet> {
|
||||
|
||||
|
@ -93,23 +97,50 @@ public class Sets extends HashMap<String, ExpansionSet> {
|
|||
* @return
|
||||
*/
|
||||
public static List<Card> generateRandomCardPool(int cardsCount, List<ColoredManaSymbol> allowedColors) {
|
||||
return generateRandomCardPool(cardsCount, allowedColors, false);
|
||||
}
|
||||
|
||||
public static List<Card> generateRandomCardPool(int cardsCount, List<ColoredManaSymbol> allowedColors, boolean onlyBasicLands) {
|
||||
CardCriteria criteria = new CardCriteria();
|
||||
criteria.notTypes(CardType.LAND);
|
||||
|
||||
if (onlyBasicLands) {
|
||||
// only lands
|
||||
criteria.rarities(Rarity.LAND);
|
||||
criteria.colorless(true); // basic lands is colorless
|
||||
} else {
|
||||
// any card, but not basic lands
|
||||
criteria.notTypes(CardType.LAND);
|
||||
|
||||
// clear colors
|
||||
criteria.white(false);
|
||||
criteria.blue(false);
|
||||
criteria.black(false);
|
||||
criteria.red(false);
|
||||
criteria.green(false);
|
||||
criteria.colorless(false); // colorless is not allowed for gen
|
||||
}
|
||||
|
||||
FilterMana manaNeed = new FilterMana();
|
||||
for (ColoredManaSymbol color : allowedColors) {
|
||||
switch (color) {
|
||||
case W:
|
||||
manaNeed.setWhite(true);
|
||||
criteria.white(true);
|
||||
break;
|
||||
case U:
|
||||
manaNeed.setBlue(true);
|
||||
criteria.blue(true);
|
||||
break;
|
||||
case B:
|
||||
manaNeed.setBlack(true);
|
||||
criteria.black(true);
|
||||
break;
|
||||
case R:
|
||||
manaNeed.setRed(true);
|
||||
criteria.red(true);
|
||||
break;
|
||||
case G:
|
||||
manaNeed.setGreen(true);
|
||||
criteria.green(true);
|
||||
break;
|
||||
}
|
||||
|
@ -123,9 +154,37 @@ public class Sets extends HashMap<String, ExpansionSet> {
|
|||
CardInfo cardInfo = cards.get(RandomUtil.nextInt(cards.size()));
|
||||
Card card = cardInfo != null ? cardInfo.getCard() : null;
|
||||
if (card != null) {
|
||||
cardPool.add(card);
|
||||
count++;
|
||||
|
||||
FilterMana manaCard = card.getColorIdentity();
|
||||
boolean cardManaOK = true;
|
||||
|
||||
if (onlyBasicLands) {
|
||||
// lands is colorless
|
||||
// discard not needed color by mana produce
|
||||
Assert.assertEquals("only basic lands allow", 1, card.getMana().size());
|
||||
for (Mana manaLand : card.getMana()) {
|
||||
if (manaLand.getWhite() > 0 && !manaNeed.isWhite()) { cardManaOK = false; }
|
||||
if (manaLand.getBlue() > 0 && !manaNeed.isBlue()) { cardManaOK = false; }
|
||||
if (manaLand.getBlack() > 0 && !manaNeed.isBlack()) { cardManaOK = false; }
|
||||
if (manaLand.getRed() > 0 && !manaNeed.isRed()) { cardManaOK = false; }
|
||||
if (manaLand.getGreen() > 0 && !manaNeed.isGreen()) { cardManaOK = false; }
|
||||
}
|
||||
} else {
|
||||
// cards
|
||||
// discard any card that have not needed color
|
||||
if (manaCard.isWhite() && !manaNeed.isWhite()) { cardManaOK = false; }
|
||||
if (manaCard.isBlue() && !manaNeed.isBlue()) { cardManaOK = false; }
|
||||
if (manaCard.isBlack() && !manaNeed.isBlack()) { cardManaOK = false; }
|
||||
if (manaCard.isRed() && !manaNeed.isRed()) { cardManaOK = false; }
|
||||
if (manaCard.isGreen() && !manaNeed.isGreen()) { cardManaOK = false; }
|
||||
}
|
||||
|
||||
if (cardManaOK) {
|
||||
cardPool.add(card);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
tries++;
|
||||
if (tries > 4096) { // to avoid infinite loop
|
||||
throw new IllegalStateException("Not enough cards for chosen colors to generate deck: " + allowedColors);
|
||||
|
|
|
@ -3773,4 +3773,22 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
public List<Designation> getDesignations() {
|
||||
return designations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerImpl obj = (PlayerImpl) o;
|
||||
if (this.getId() == null || obj.getId() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.getId().equals(obj.getId());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue