Get rid of global static Card cache and hang it off the Game instead.

This paves the way for having multiple simulataneous game objects (e.g. for simulation).
This commit is contained in:
Myrd
2014-12-28 16:31:23 +00:00
parent 5fe82c5758
commit bf34aec4fc
17 changed files with 115 additions and 109 deletions

View File

@@ -42,6 +42,7 @@ import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardView;
import forge.game.combat.Combat;
import forge.game.event.GameEvent;
import forge.game.event.GameEventGameOutcome;
@@ -110,9 +111,20 @@ public class Game {
playerCache.put(id, player);
}
public Game(List<RegisteredPlayer> players0, GameRules rules0, Match match0) { /* no more zones to map here */
Card.clearCache();
public GameEntityCache<Card, CardView> cardCache = new GameEntityCache<>();
public Card getCard(CardView cardView) {
return cardCache.get(cardView);
}
public void addCard(Integer id, Card card) {
cardCache.put(id, card);
}
public CardCollection getCardList(Iterable<CardView> cardViews) {
CardCollection list = new CardCollection();
cardCache.addToList(cardViews, list);
return list;
}
public Game(List<RegisteredPlayer> players0, GameRules rules0, Match match0) { /* no more zones to map here */
rules = rules0;
match = match0;
@@ -127,7 +139,7 @@ public class Game {
int plId = 0;
for (RegisteredPlayer psc : players0) {
IGameEntitiesFactory factory = (IGameEntitiesFactory)psc.getPlayer();
IGameEntitiesFactory factory = (IGameEntitiesFactory)psc.getPlayer();
Player pl = factory.createIngamePlayer(this, plId++);
allPlayers.add(pl);
ingamePlayers.add(pl);

View File

@@ -97,13 +97,13 @@ public class ChooseSourceEffect extends SpellAbilityEffect {
commandZoneSources = CardLists.filterControlledBy(commandZoneSources, tgtPlayers.get(0));
}
Card divPermanentSources = new Card(-1);
Card divPermanentSources = new Card(-1, game);
divPermanentSources.setName("--PERMANENTS:--");
Card divStackSources = new Card(-2);
Card divStackSources = new Card(-2, game);
divStackSources.setName("--SPELLS ON THE STACK:--");
Card divReferencedSources = new Card(-3);
Card divReferencedSources = new Card(-3, game);
divReferencedSources.setName("--OBJECTS REFERRED TO ON THE STACK:--");
Card divCommandZoneSources = new Card(-4);
Card divCommandZoneSources = new Card(-4, game);
divCommandZoneSources.setName("--CARDS IN THE COMMAND ZONE:--");
if (permanentSources.size() > 0) {

View File

@@ -27,13 +27,12 @@ public class DamageDealEffect extends SpellAbilityEffect {
final String damage = sa.getParam("NumDmg");
final int dmg = AbilityUtils.calculateAmount(sa.getHostCard(), damage, sa);
List<GameObject> tgts = getTargets(sa);
if (tgts.isEmpty())
return "";
final List<Card> definedSources = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DamageSource"), sa);
Card source = definedSources.isEmpty() ? new Card(-1) : definedSources.get(0);
Card source = definedSources.isEmpty() ? new Card(-1, sa.getHostCard().getGame()) : definedSources.get(0);
if (source != sa.getHostCard()) {
sb.append(source.toString()).append(" deals");

View File

@@ -8,7 +8,7 @@ public class DetachedCardEffect extends Card {
private Card card; //card linked to effect
public DetachedCardEffect(Card card0, String name0) {
super(card0.getOwner().getGame().nextCardId(), card0.getPaperCard());
super(card0.getOwner().getGame().nextCardId(), card0.getPaperCard(), card0.getOwner().getGame());
card = card0;
setName(name0);

View File

@@ -106,7 +106,7 @@ public class EffectEffect extends SpellAbilityEffect {
}
final Player controller = sa.hasParam("EffectOwner") ? ownerEff : sa.getActivatingPlayer();
final Card eff = new Card(controller.getGame().nextCardId());
final Card eff = new Card(game.nextCardId(), game);
eff.setName(name);
eff.addType("Effect"); // Or Emblem
eff.setToken(true); // Set token to true, so when leaving play it gets nuked

View File

@@ -65,13 +65,13 @@ public class PlayLandVariantEffect extends SpellAbilityEffect {
cards = Lists.newArrayList(Iterables.filter(cards, cp));
// get a random basic land
PaperCard ran = Aggregates.random(cards);
Card random = CardFactory.getCard(ran, activator);
Card random = CardFactory.getCard(ran, activator, source.getGame());
// if activator cannot play the random land, loop
while (!activator.canPlayLand(random, false) && !cards.isEmpty()) {
cards.remove(ran);
if (cards.isEmpty()) return;
ran = Aggregates.random(cards);
random = CardFactory.getCard(ran, activator);
random = CardFactory.getCard(ran, activator, game);
}
String imageFileName = game.getRules().canCloneUseTargetsImage ? source.getImageKey() : random.getImageKey();

View File

@@ -90,25 +90,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
* @version $Id$
*/
public class Card extends GameEntity implements Comparable<Card> {
private static HashMap<Integer, Card> cardCache = new HashMap<Integer, Card>();
public static Card get(CardView cardView) {
if (cardView == null) { return null; }
return cardCache.get(cardView.getId());
}
public static CardCollection getList(Iterable<CardView> cardViews) {
CardCollection list = new CardCollection();
for (CardView cv : cardViews) {
Card c = get(cv);
if (c != null) {
list.add(c);
}
}
return list;
}
public static void clearCache() {
cardCache.clear();
}
private final Game game;
private final IPaperCard paperCard;
private final Map<CardStateName, CardState> states = new EnumMap<CardStateName, CardState>(CardStateName.class);
@@ -264,8 +246,8 @@ public class Card extends GameEntity implements Comparable<Card> {
* Instantiates a new card not associated to any paper card.
* @param id the unique id of the new card.
*/
public Card(final int id0) {
this(id0, null, true);
public Card(final int id0, final Game game0) {
this(id0, null, true, game0);
}
/**
@@ -276,18 +258,19 @@ public class Card extends GameEntity implements Comparable<Card> {
* card.
* @see IPaperCard
*/
public Card(final int id0, final IPaperCard paperCard0) {
this(id0, paperCard0, true);
public Card(final int id0, final IPaperCard paperCard0, final Game game0) {
this(id0, paperCard0, true, game0);
}
public Card(final int id0, final IPaperCard paperCard0, final boolean allowCache) {
public Card(final int id0, final IPaperCard paperCard0, final boolean allowCache, final Game game0) {
super(id0);
if (id0 >= 0 && allowCache) {
cardCache.put(id0, this);
game = game0;
if (id0 >= 0 && allowCache && game != null) {
game.addCard(id0, this);
}
paperCard = paperCard0;
view = new CardView(id0);
currentState = new CardState(view.getCurrentState());
currentState = new CardState(view.getCurrentState(), this);
states.put(CardStateName.Original, currentState);
states.put(CardStateName.FaceDown, CardUtil.getFaceDownCharacteristic(this));
view.updateChangedColorWords(this);
@@ -399,7 +382,7 @@ public class Card extends GameEntity implements Comparable<Card> {
}
public final void addAlternateState(final CardStateName state, final boolean updateView) {
states.put(state, new CardState(view.createAlternateState(state)));
states.put(state, new CardState(view.createAlternateState(state), this));
if (updateView) {
view.updateState(this);
}
@@ -2103,6 +2086,10 @@ public class Card extends GameEntity implements Comparable<Card> {
}
public final void setOwner(final Player owner0) {
if (owner == owner0) { return; }
if (owner != null && owner.getGame() != this.getGame()) {
// Sanity check.
throw new RuntimeException();
}
owner = owner0;
view.updateOwner(this);
view.updateController(this);
@@ -6258,20 +6245,9 @@ public class Card extends GameEntity implements Comparable<Card> {
public Iterable<OptionalCost> getOptionalCostsPaid() { return costsPaid; }
public boolean isOptionalCostPaid(OptionalCost cost) { return costsPaid.contains(cost); }
/**
* Fetch GameState for this card from references to players who may own or control this card.
*/
@Override
public Game getGame() {
Player controller = getController();
if (controller != null) {
return controller.getGame();
}
Player owner = getOwner();
if (owner != null) {
return owner.getGame();
}
return null;
return game;
}
public List<SpellAbility> getAllPossibleAbilities(final Player player, final boolean removeUnplayable) {
@@ -6308,7 +6284,7 @@ public class Card extends GameEntity implements Comparable<Card> {
}
public static Card fromPaperCard(IPaperCard pc, Player owner) {
return CardFactory.getCard(pc, owner);
return CardFactory.getCard(pc, owner, owner == null ? null : owner.getGame());
}
private static final Map<PaperCard, Card> cp2card = new HashMap<PaperCard, Card>();

View File

@@ -24,6 +24,7 @@ import forge.card.CardSplitType;
import forge.card.CardType;
import forge.card.ICardFace;
import forge.card.mana.ManaCost;
import forge.game.Game;
import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
@@ -75,10 +76,11 @@ public class CardFactory {
public final static Card copyCard(final Card in, boolean assignNewId) {
Card out;
if (!(in.isToken() || in.getCopiedPermanent() != null)) {
out = assignNewId ? getCard(in.getPaperCard(), in.getOwner())
: getCard(in.getPaperCard(), in.getOwner(), in.getId());
out = assignNewId ? getCard(in.getPaperCard(), in.getOwner(), in.getGame())
: getCard(in.getPaperCard(), in.getOwner(), in.getId(), in.getGame());
} else { // token
out = assignNewId ? new Card(in.getGame().nextCardId(), in.getPaperCard()) : new Card(in.getId(), in.getPaperCard());
int id = assignNewId ? in.getGame().nextCardId() : in.getId();
out = new Card(id, in.getPaperCard(), in.getGame());
out = CardFactory.copyStats(in, in.getController());
out.setToken(true);
@@ -89,7 +91,7 @@ public class CardFactory {
}
for (final CardStateName state : in.getStates()) {
CardFactory.copyState(in, state, out, state);
CardFactory.copyState(in, state, out, state);
}
out.setState(in.getCurrentStateName(), true);
@@ -210,13 +212,13 @@ public class CardFactory {
return copySA;
}
public final static Card getCard(final IPaperCard cp, final Player owner) {
return getCard(cp, owner, owner == null ? -1 : owner.getGame().nextCardId());
public final static Card getCard(final IPaperCard cp, final Player owner, final Game game) {
return getCard(cp, owner, owner == null ? -1 : owner.getGame().nextCardId(), game);
}
public final static Card getCard(final IPaperCard cp, final Player owner, final int cardId) {
public final static Card getCard(final IPaperCard cp, final Player owner, final int cardId, final Game game) {
//System.out.println(cardName);
CardRules cardRules = cp.getRules();
final Card c = readCard(cardRules, cp, cardId);
final Card c = readCard(cardRules, cp, cardId, game);
c.setRules(cardRules);
c.setOwner(owner);
buildAbilities(c);
@@ -341,8 +343,8 @@ public class CardFactory {
card.setSVar("DamagePWY", "Count$YourLifeTotal");
}
private static Card readCard(final CardRules rules, final IPaperCard paperCard, int cardId) {
final Card card = new Card(cardId, paperCard);
private static Card readCard(final CardRules rules, final IPaperCard paperCard, int cardId, Game game) {
final Card card = new Card(cardId, paperCard, game);
// 1. The states we may have:
CardSplitType st = rules.getSplitType();
@@ -428,7 +430,7 @@ public class CardFactory {
*/
public static Card copyCopiableCharacteristics(final Card from, final Player newOwner) {
int id = newOwner == null ? 0 : newOwner.getGame().nextCardId();
final Card c = new Card(id, from.getPaperCard());
final Card c = new Card(id, from.getPaperCard(), from.getGame());
c.setOwner(newOwner);
c.setSetCode(from.getSetCode());
@@ -511,7 +513,7 @@ public class CardFactory {
*/
public static Card copyStats(final Card in, final Player newOwner) {
int id = newOwner == null ? 0 : newOwner.getGame().nextCardId();
final Card c = new Card(id, in.getPaperCard());
final Card c = new Card(id, in.getPaperCard(), in.getGame());
c.setOwner(newOwner);
c.setSetCode(in.getSetCode());
@@ -607,7 +609,7 @@ public class CardFactory {
final String manaCost, final String[] types, final int basePower, final int baseToughness,
final String[] intrinsicKeywords) {
final List<Card> list = new ArrayList<Card>();
final Card c = new Card(controller.getGame().nextCardId());
final Card c = new Card(controller.getGame().nextCardId(), controller.getGame());
c.setName(name);
c.setImageKey(ImageKeys.getTokenKey(imageName));

View File

@@ -64,9 +64,11 @@ public class CardState {
private String setCode = CardEdition.UNKNOWN.getCode();
private final CardStateView view;
private final Card card;
public CardState(CardStateView view0) {
public CardState(CardStateView view0, Card card0) {
view = view0;
card = card0;
view.updateRarity(this);
view.updateSetCode(this);
}
@@ -75,6 +77,10 @@ public class CardState {
return view;
}
public Card getCard() {
return card;
}
public final String getName() {
return name;
}

View File

@@ -213,7 +213,7 @@ public final class CardUtil {
* @return a copy of C with LastKnownInfo stuff retained.
*/
public static Card getLKICopy(final Card in) {
final Card newCopy = new Card(in.getId(), in.getPaperCard(), false);
final Card newCopy = new Card(in.getId(), in.getPaperCard(), false, in.getGame());
newCopy.setSetCode(in.getSetCode());
newCopy.setOwner(in.getOwner());
newCopy.setController(in.getController(), 0);
@@ -285,7 +285,7 @@ public final class CardUtil {
final CardType type = new CardType();
type.add("Creature");
final CardState ret = new CardState(c.getView().createAlternateState(CardStateName.FaceDown));
final CardState ret = new CardState(c.getView().createAlternateState(CardStateName.FaceDown), c);
ret.setBasePower(2);
ret.setBaseToughness(2);

View File

@@ -752,7 +752,7 @@ public class CardView extends GameEntityView {
setName(c.getName());
if (CardView.this.getCurrentState() == this) {
Card card = Card.get(CardView.this);
Card card = c.getCard();
if (card != null) {
CardView.this.updateName(card);
}
@@ -794,7 +794,7 @@ public class CardView extends GameEntityView {
void updateType(CardState c) {
CardTypeView type = c.getType();
if (CardView.this.getCurrentState() == this) {
Card card = Card.get(CardView.this);
Card card = c.getCard();
if (card != null) {
type = type.getTypeWithChanges(card.getChangedCardTypes()); //TODO: find a better way to do this
updateRulesText(card.getRules(), type);
@@ -842,7 +842,7 @@ public class CardView extends GameEntityView {
}
}
void updatePower(CardState c) {
Card card = Card.get(CardView.this);
Card card = c.getCard();
if (card != null) {
updatePower(card); //TODO: find a better way to do this
return;
@@ -862,7 +862,7 @@ public class CardView extends GameEntityView {
}
}
void updateToughness(CardState c) {
Card card = Card.get(CardView.this);
Card card = c.getCard();
if (card != null) {
updateToughness(card); //TODO: find a better way to do this
return;
@@ -878,7 +878,7 @@ public class CardView extends GameEntityView {
}
void updateLoyalty(CardState c) {
if (CardView.this.getCurrentState() == this) {
Card card = Card.get(CardView.this);
Card card = c.getCard();
if (card != null) {
updateLoyalty(card); //TODO: find a better way to do this
return;