mirror of
https://github.com/correl/mage.git
synced 2024-12-25 03:00:15 +00:00
* Server: fixed that too much permanents or mana sources on battlefield can crush or slow down the server (#6938);
This commit is contained in:
parent
de110a92dd
commit
3430013f8d
2 changed files with 61 additions and 16 deletions
|
@ -343,4 +343,28 @@ public class ConvokeTest extends CardTestPlayerBaseWithAIHelps {
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Hogaak, Arisen Necropolis", 1);
|
assertPermanentCount(playerA, "Hogaak, Arisen Necropolis", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_Mana_MemoryOverflow() {
|
||||||
|
// possible bug: convoke mana calculation can overflow server's memory (too much mana options from too much permanents)
|
||||||
|
// https://github.com/magefree/mage/issues/6938
|
||||||
|
|
||||||
|
// Create X 1/1 white Soldier creature tokens with lifelink.
|
||||||
|
// Convoke (Your creatures can help cast this spell. Each creature you tap while casting this spell pays for {1} or one mana of that creature’s color.)
|
||||||
|
addCard(Zone.HAND, playerA, "March of the Multitudes", 1); // {X}{G}{W}{W}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 500);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "March of the Multitudes");
|
||||||
|
setChoice(playerA, "X=1");
|
||||||
|
addTarget(playerA, "Grizzly Bears"); // convoke pay
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Soldier", 1);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,30 +1,27 @@
|
||||||
package mage.abilities.mana;
|
package mage.abilities.mana;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.costs.Cost;
|
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.events.ManaEvent;
|
import mage.game.events.ManaEvent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*
|
* <p>
|
||||||
* this class is used to build a list of all possible mana combinations it can
|
* this class is used to build a list of all possible mana combinations it can
|
||||||
* be used to find all the ways to pay a mana cost or all the different mana
|
* be used to find all the ways to pay a mana cost or all the different mana
|
||||||
* combinations available to a player
|
* combinations available to a player
|
||||||
*
|
* <p>
|
||||||
* TODO: Conditional Mana is not supported yet. The mana adding removes the
|
* TODO: Conditional Mana is not supported yet. The mana adding removes the
|
||||||
* condition of conditional mana
|
* condition of conditional mana
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class ManaOptions extends ArrayList<Mana> {
|
public class ManaOptions extends ArrayList<Mana> {
|
||||||
|
|
||||||
|
@ -87,6 +84,8 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forceManaDeduplication();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addManaVariation(List<Mana> netManas, ActivatedManaAbilityImpl ability, Game game) {
|
private void addManaVariation(List<Mana> netManas, ActivatedManaAbilityImpl ability, Game game) {
|
||||||
|
@ -102,6 +101,8 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forceManaDeduplication();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<List<Mana>> getSimulatedTriggeredManaFromPlayer(Game game, Ability ability) {
|
private static List<List<Mana>> getSimulatedTriggeredManaFromPlayer(Game game, Ability ability) {
|
||||||
|
@ -189,9 +190,9 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
if (startingMana.includesMana(manaCosts)) { // can pay the mana costs to use the ability
|
if (startingMana.includesMana(manaCosts)) { // can pay the mana costs to use the ability
|
||||||
if (!subtractCostAddMana(manaCosts, triggeredManaVariation, ability.getCosts().isEmpty(), startingMana)) {
|
if (!subtractCostAddMana(manaCosts, triggeredManaVariation, ability.getCosts().isEmpty(), startingMana)) {
|
||||||
// the starting mana includes mana parts that the increased mana does not include, so add starting mana also as an option
|
// the starting mana includes mana parts that the increased mana does not include, so add starting mana also as an option
|
||||||
add(prevMana);
|
add(prevMana);
|
||||||
}
|
}
|
||||||
wasUsable = true;
|
wasUsable = true;
|
||||||
} else {
|
} else {
|
||||||
// mana costs can't be paid so keep starting mana
|
// mana costs can't be paid so keep starting mana
|
||||||
add(prevMana);
|
add(prevMana);
|
||||||
|
@ -251,10 +252,13 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.size() > 30 || replaces > 30) {
|
if (this.size() > 30 || replaces > 30) {
|
||||||
logger.trace("ManaOptionsCosts " + this.size() + " Ign:" + replaces + " => " + this.toString());
|
logger.trace("ManaOptionsCosts " + this.size() + " Ign:" + replaces + " => " + this.toString());
|
||||||
logger.trace("Abilities: " + abilities.toString());
|
logger.trace("Abilities: " + abilities.toString());
|
||||||
}
|
}
|
||||||
|
forceManaDeduplication();
|
||||||
|
|
||||||
return wasUsable;
|
return wasUsable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +306,8 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forceManaDeduplication();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMana(Mana addMana) {
|
public void addMana(Mana addMana) {
|
||||||
|
@ -311,6 +317,8 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
for (Mana mana : this) {
|
for (Mana mana : this) {
|
||||||
mana.add(addMana);
|
mana.add(addMana);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forceManaDeduplication();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMana(ManaOptions options) {
|
public void addMana(ManaOptions options) {
|
||||||
|
@ -335,6 +343,17 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forceManaDeduplication();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forceManaDeduplication() {
|
||||||
|
// memory overflow protection - force de-duplication on too much mana sources
|
||||||
|
// bug example: https://github.com/magefree/mage/issues/6938
|
||||||
|
// use it after new mana adding
|
||||||
|
if (this.size() > 1000) {
|
||||||
|
this.removeDuplicated();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManaOptions copy() {
|
public ManaOptions copy() {
|
||||||
|
@ -408,14 +427,16 @@ public class ManaOptions extends ArrayList<Mana> {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forceManaDeduplication();
|
||||||
|
|
||||||
return oldManaWasReplaced;
|
return oldManaWasReplaced;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @param number of generic mana
|
||||||
* @param number of generic mana
|
|
||||||
* @param manaAvailable
|
* @param manaAvailable
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static List<Mana> getPossiblePayCombinations(int number, Mana manaAvailable) {
|
public static List<Mana> getPossiblePayCombinations(int number, Mana manaAvailable) {
|
||||||
List<Mana> payCombinations = new ArrayList<>();
|
List<Mana> payCombinations = new ArrayList<>();
|
||||||
|
|
Loading…
Reference in a new issue