forked from External/mage
Costs Tag Tracking part 2: Tag system and X values, reworked deep copy code (#11406)
* Implement Costs Tag Map system * Use Costs Tag Map system to store X value for spells, abilities, and resolving permanents * Store Bestow without target's tags Change functions for getting tags and storing the tags of a new permanent * Create and use deep copy function in CardUtil, add Copyable<T> to many classes * Fix Hall Of the Bandit Lord infinite loop * Add additional comments * Don't store null/empty costs tags maps (saves memory) * Fix two more Watchers with Ability variable * Add check for exact collection types during deep copy * Use generics instead of pure type erasure during deep copy * convert more code to using deep copy helper, everything use Object copier, add EnumMap * fix documentation * Don't need the separate null checks anymore (handled in deepCopyObject) * Minor cleanup
This commit is contained in:
parent
72e30f1574
commit
bea33c7493
29 changed files with 458 additions and 338 deletions
|
|
@ -101,6 +101,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
private Map<UUID, Zone> zones = new HashMap<>();
|
||||
private List<GameEvent> simultaneousEvents = new ArrayList<>();
|
||||
private Map<UUID, CardState> cardState = new HashMap<>();
|
||||
private Map<MageObjectReference, Map<String, Object>> permanentCostsTags = new HashMap<>(); // Permanent reference -> map of (tag -> values) describing how the permanent's spell was cast
|
||||
private Map<UUID, MageObjectAttribute> mageObjectAttribute = new HashMap<>();
|
||||
private Map<UUID, Integer> zoneChangeCounter = new HashMap<>();
|
||||
private Map<UUID, Card> copiedCards = new HashMap<>();
|
||||
|
|
@ -162,36 +163,19 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
this.stepNum = state.stepNum;
|
||||
this.extraTurnId = state.extraTurnId;
|
||||
this.effects = state.effects.copy();
|
||||
for (TriggeredAbility trigger : state.triggered) {
|
||||
this.triggered.add(trigger.copy());
|
||||
}
|
||||
this.triggered = CardUtil.deepCopyObject(state.triggered);
|
||||
this.triggers = state.triggers.copy();
|
||||
this.delayed = state.delayed.copy();
|
||||
this.specialActions = state.specialActions.copy();
|
||||
this.combat = state.combat.copy();
|
||||
this.turnMods = state.turnMods.copy();
|
||||
this.watchers = state.watchers.copy();
|
||||
for (Map.Entry<String, Object> entry : state.values.entrySet()) {
|
||||
if (entry.getValue() instanceof HashSet) {
|
||||
this.values.put(entry.getKey(), ((HashSet) entry.getValue()).clone());
|
||||
} else if (entry.getValue() instanceof EnumSet) {
|
||||
this.values.put(entry.getKey(), ((EnumSet) entry.getValue()).clone());
|
||||
} else if (entry.getValue() instanceof HashMap) {
|
||||
this.values.put(entry.getKey(), ((HashMap) entry.getValue()).clone());
|
||||
} else if (entry.getValue() instanceof List) {
|
||||
this.values.put(entry.getKey(), ((List) entry.getValue()).stream().collect(Collectors.toList()));
|
||||
} else {
|
||||
this.values.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
this.values = CardUtil.deepCopyObject(state.values);
|
||||
this.zones.putAll(state.zones);
|
||||
this.simultaneousEvents.addAll(state.simultaneousEvents);
|
||||
for (Map.Entry<UUID, CardState> entry : state.cardState.entrySet()) {
|
||||
cardState.put(entry.getKey(), entry.getValue().copy());
|
||||
}
|
||||
for (Map.Entry<UUID, MageObjectAttribute> entry : state.mageObjectAttribute.entrySet()) {
|
||||
mageObjectAttribute.put(entry.getKey(), entry.getValue().copy());
|
||||
}
|
||||
this.cardState = CardUtil.deepCopyObject(state.cardState);
|
||||
this.permanentCostsTags = CardUtil.deepCopyObject(state.permanentCostsTags);
|
||||
this.mageObjectAttribute = CardUtil.deepCopyObject(state.mageObjectAttribute);
|
||||
this.zoneChangeCounter.putAll(state.zoneChangeCounter);
|
||||
this.copiedCards.putAll(state.copiedCards);
|
||||
this.permanentOrderNumber = state.permanentOrderNumber;
|
||||
|
|
@ -231,6 +215,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
gameOver = false;
|
||||
specialActions.clear();
|
||||
cardState.clear();
|
||||
permanentCostsTags.clear();
|
||||
combat.clear();
|
||||
turnMods.clear();
|
||||
watchers.clear();
|
||||
|
|
@ -280,6 +265,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
this.zones = state.zones;
|
||||
this.simultaneousEvents = state.simultaneousEvents;
|
||||
this.cardState = state.cardState;
|
||||
this.permanentCostsTags = state.permanentCostsTags;
|
||||
this.mageObjectAttribute = state.mageObjectAttribute;
|
||||
this.zoneChangeCounter = state.zoneChangeCounter;
|
||||
this.copiedCards = state.copiedCards;
|
||||
|
|
@ -1369,6 +1355,29 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
return mageObjectAtt;
|
||||
}
|
||||
|
||||
public Map<MageObjectReference, Map<String, Object>> getPermanentCostsTags() {
|
||||
return permanentCostsTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the tags of source ability using the MOR as a reference
|
||||
*/
|
||||
void storePermanentCostsTags(MageObjectReference permanentMOR, Ability source){
|
||||
if (source.getCostsTagMap() != null) {
|
||||
permanentCostsTags.put(permanentMOR, CardUtil.deepCopyObject(source.getCostsTagMap()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the cost tags if the corresponding permanent is no longer on the battlefield.
|
||||
* Only use if the stack is empty and nothing can refer to them anymore (such as at EOT, the current behavior)
|
||||
*/
|
||||
public void cleanupPermanentCostsTags(Game game){
|
||||
getPermanentCostsTags().entrySet().removeIf(entry ->
|
||||
!(entry.getKey().zoneCounterIsCurrent(game))
|
||||
);
|
||||
}
|
||||
|
||||
public void addWatcher(Watcher watcher) {
|
||||
this.watchers.add(watcher);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue