diff --git a/game-app/game-core/src/main/java/games/strategy/engine/framework/GameDataManager.java b/game-app/game-core/src/main/java/games/strategy/engine/framework/GameDataManager.java
index cdf35a41f12..31387b6e3c9 100644
--- a/game-app/game-core/src/main/java/games/strategy/engine/framework/GameDataManager.java
+++ b/game-app/game-core/src/main/java/games/strategy/engine/framework/GameDataManager.java
@@ -20,6 +20,7 @@
import java.util.Optional;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
+import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.triplea.game.server.HeadlessGameServer;
@@ -191,7 +192,7 @@ public static void saveGame(
try (OutputStream os = Files.newOutputStream(tempFile);
OutputStream bufferedOutStream = new BufferedOutputStream(os);
OutputStream zippedOutStream = new GZIPOutputStream(bufferedOutStream)) {
- saveGameUncompressed(zippedOutStream, gameData, true, engineVersion);
+ saveGameUncompressed(zippedOutStream, gameData, Options.withEverything(), engineVersion);
}
// now write to sink (ensure sink is closed per method contract)
@@ -204,10 +205,25 @@ public static void saveGame(
}
}
+ @Builder
+ public static class Options {
+ @Builder.Default boolean withDelegates = false;
+ @Builder.Default boolean withHistory = false;
+ @Builder.Default boolean withAttachmentXmlData = false;
+
+ public static Options withEverything() {
+ return builder().withDelegates(true).withHistory(true).withAttachmentXmlData(true).build();
+ }
+
+ public static Options forBattleCalculator() {
+ return builder().build();
+ }
+ }
+
public static void saveGameUncompressed(
final OutputStream sink,
final GameData data,
- final boolean saveDelegateInfoHistoryAndAttachmentsOrder,
+ final Options options,
final Version engineVersion)
throws IOException {
// write to temporary file first in case of error
@@ -215,19 +231,26 @@ public static void saveGameUncompressed(
outStream.writeObject(engineVersion);
data.acquireReadLock();
try {
- if (saveDelegateInfoHistoryAndAttachmentsOrder) {
- outStream.writeObject(data);
- writeDelegates(data, outStream);
- } else {
- // TODO: Attachment order data is only used for XML export and takes up lots of memory.
- // Could we remove it and just get the info again from the XML when exporting?
- final var attachments = data.getAttachmentOrderAndValues();
- final var history = data.getHistory();
- data.setAttachmentOrderAndValues(null);
+ final var history = data.getHistory();
+ if (!options.withHistory) {
data.resetHistory();
- outStream.writeObject(data);
+ }
+ // TODO: Attachment order data is only used for XML export and takes up lots of memory.
+ // Could we remove it and just get the info again from the XML when exporting?
+ final var attachments = data.getAttachmentOrderAndValues();
+ if (!options.withAttachmentXmlData) {
+ data.setAttachmentOrderAndValues(null);
+ }
+ outStream.writeObject(data);
+ if (!options.withAttachmentXmlData) {
data.setAttachmentOrderAndValues(attachments);
+ }
+ if (!options.withHistory) {
data.setHistory(history);
+ }
+ if (options.withDelegates) {
+ writeDelegates(data, outStream);
+ } else {
outStream.writeObject(DELEGATE_LIST_END);
}
} finally {
diff --git a/game-app/game-core/src/main/java/games/strategy/engine/framework/GameDataUtils.java b/game-app/game-core/src/main/java/games/strategy/engine/framework/GameDataUtils.java
index dc1bc8195bb..e171c20dc6d 100644
--- a/game-app/game-core/src/main/java/games/strategy/engine/framework/GameDataUtils.java
+++ b/game-app/game-core/src/main/java/games/strategy/engine/framework/GameDataUtils.java
@@ -2,11 +2,11 @@
import games.strategy.engine.data.GameData;
import games.strategy.engine.data.GameObjectOutputStream;
-import games.strategy.engine.history.History;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Optional;
+import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.triplea.injection.Injections;
import org.triplea.io.IoUtils;
@@ -14,24 +14,10 @@
/** A collection of useful methods for working with instances of {@link GameData}. */
@Slf4j
+@UtilityClass
public final class GameDataUtils {
- private GameDataUtils() {}
-
- /**
- * Create a deep copy of GameData without history as it can get large. You should have the
- * game data's write lock before calling this method
- */
- public static Optional cloneGameDataWithoutHistory(
- final GameData data, final boolean copyDelegates, final Version engineVersion) {
- final History temp = data.getHistory();
- data.resetHistory();
- final Optional dataCopy = cloneGameData(data, copyDelegates, engineVersion);
- data.setHistory(temp);
- return dataCopy;
- }
-
- public static Optional cloneGameData(final GameData data) {
- return cloneGameData(data, false, Injections.getInstance().getEngineVersion());
+ public static Optional cloneGameData(GameData data, GameDataManager.Options options) {
+ return cloneGameData(data, options, Injections.getInstance().getEngineVersion());
}
/**
@@ -39,8 +25,8 @@ public static Optional cloneGameData(final GameData data) {
* before calling this method
*/
public static Optional cloneGameData(
- final GameData data, final boolean copyDelegates, final Version engineVersion) {
- final byte[] bytes = gameDataToBytes(data, copyDelegates, engineVersion).orElse(null);
+ GameData data, GameDataManager.Options options, Version engineVersion) {
+ final byte[] bytes = gameDataToBytes(data, options, engineVersion).orElse(null);
if (bytes != null) {
return createGameDataFromBytes(bytes, engineVersion);
}
@@ -48,11 +34,11 @@ public static Optional cloneGameData(
}
public static Optional gameDataToBytes(
- GameData data, boolean copyDelegates, Version engineVersion) {
+ GameData data, GameDataManager.Options options, Version engineVersion) {
try {
return Optional.of(
IoUtils.writeToMemory(
- os -> GameDataManager.saveGameUncompressed(os, data, copyDelegates, engineVersion)));
+ os -> GameDataManager.saveGameUncompressed(os, data, options, engineVersion)));
} catch (final IOException e) {
log.error("Failed to clone game data", e);
return Optional.empty();
diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/AbstractProAi.java b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/AbstractProAi.java
index ec32ddc4d7c..4b34bef4dd2 100644
--- a/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/AbstractProAi.java
+++ b/game-app/game-core/src/main/java/games/strategy/triplea/ai/pro/AbstractProAi.java
@@ -7,6 +7,7 @@
import games.strategy.engine.data.Territory;
import games.strategy.engine.data.Unit;
import games.strategy.engine.delegate.IDelegateBridge;
+import games.strategy.engine.framework.GameDataManager;
import games.strategy.engine.framework.GameDataUtils;
import games.strategy.triplea.Properties;
import games.strategy.triplea.ai.AbstractBuiltInAi;
@@ -180,8 +181,10 @@ protected void purchase(
try {
data.acquireWriteLock();
dataCopy =
- GameDataUtils.cloneGameDataWithoutHistory(
- data, true, Injections.getInstance().getEngineVersion())
+ GameDataUtils.cloneGameData(
+ data,
+ GameDataManager.Options.builder().withDelegates(true).build(),
+ Injections.getInstance().getEngineVersion())
.orElse(null);
if (dataCopy == null) {
return;
diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/BattleCalculator.java b/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/BattleCalculator.java
index 57910d5e2b5..b2ff52820e6 100644
--- a/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/BattleCalculator.java
+++ b/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/BattleCalculator.java
@@ -9,6 +9,7 @@
import games.strategy.engine.data.TerritoryEffect;
import games.strategy.engine.data.Unit;
import games.strategy.engine.data.changefactory.ChangeFactory;
+import games.strategy.engine.framework.GameDataManager;
import games.strategy.engine.framework.GameDataUtils;
import games.strategy.triplea.delegate.GameDelegateBridge;
import games.strategy.triplea.delegate.battle.BattleResults;
@@ -38,7 +39,10 @@ private BattleCalculator(@Nullable GameData data) {
}
BattleCalculator(GameData data, Version engineVersion) {
- this(GameDataUtils.cloneGameData(data, false, engineVersion).orElse(null));
+ this(
+ GameDataUtils.cloneGameData(
+ data, GameDataManager.Options.forBattleCalculator(), engineVersion)
+ .orElse(null));
}
BattleCalculator(byte[] data, Version engineVersion) {
diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/ConcurrentBattleCalculator.java b/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/ConcurrentBattleCalculator.java
index 6a6b5639b58..c42c830353c 100644
--- a/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/ConcurrentBattleCalculator.java
+++ b/game-app/game-core/src/main/java/games/strategy/triplea/odds/calculator/ConcurrentBattleCalculator.java
@@ -6,6 +6,7 @@
import games.strategy.engine.data.Territory;
import games.strategy.engine.data.TerritoryEffect;
import games.strategy.engine.data.Unit;
+import games.strategy.engine.framework.GameDataManager;
import games.strategy.engine.framework.GameDataUtils;
import java.util.Collection;
import java.util.List;
@@ -127,7 +128,10 @@ private void createWorkers(final GameData data) {
// Serialize the data, then release lock on it so game can continue (ie: we don't want to
// lock on it while we copy it 16 times).
data.acquireWriteLock();
- serializedData = GameDataUtils.gameDataToBytes(data, false, engineVersion).orElse(null);
+ serializedData =
+ GameDataUtils.gameDataToBytes(
+ data, GameDataManager.Options.forBattleCalculator(), engineVersion)
+ .orElse(null);
if (serializedData == null) {
return;
}
diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/ui/TripleAFrame.java b/game-app/game-core/src/main/java/games/strategy/triplea/ui/TripleAFrame.java
index c53998c551a..0d8d2f2b692 100644
--- a/game-app/game-core/src/main/java/games/strategy/triplea/ui/TripleAFrame.java
+++ b/game-app/game-core/src/main/java/games/strategy/triplea/ui/TripleAFrame.java
@@ -1763,7 +1763,8 @@ private void showHistory() {
try {
// we want to use a clone of the data, so we can make changes to it as we walk up and down the
// history
- clonedGameData = GameDataUtils.cloneGameData(data).orElse(null);
+ final var cloneOptions = GameDataManager.Options.builder().withHistory(true).build();
+ clonedGameData = GameDataUtils.cloneGameData(data, cloneOptions).orElse(null);
if (clonedGameData == null) {
return;
}
@@ -1878,7 +1879,9 @@ public void actionPerformed(final ActionEvent ae) {
try (OutputStream fileOutputStream = Files.newOutputStream(f.get())) {
final GameData datacopy =
GameDataUtils.cloneGameData(
- data, true, Injections.getInstance().getEngineVersion())
+ data,
+ GameDataManager.Options.withEverything(),
+ Injections.getInstance().getEngineVersion())
.orElse(null);
if (datacopy != null) {
datacopy.getHistory().gotoNode(historyPanel.getCurrentPopupNode());
diff --git a/game-app/game-core/src/main/java/games/strategy/triplea/ui/menubar/ExportMenu.java b/game-app/game-core/src/main/java/games/strategy/triplea/ui/menubar/ExportMenu.java
index 9cb2e0a6bdb..ac37f94589d 100644
--- a/game-app/game-core/src/main/java/games/strategy/triplea/ui/menubar/ExportMenu.java
+++ b/game-app/game-core/src/main/java/games/strategy/triplea/ui/menubar/ExportMenu.java
@@ -7,6 +7,7 @@
import games.strategy.engine.data.Resource;
import games.strategy.engine.data.UnitType;
import games.strategy.engine.data.export.GameDataExporter;
+import games.strategy.engine.framework.GameDataManager;
import games.strategy.engine.framework.GameDataUtils;
import games.strategy.engine.framework.system.SystemProperties;
import games.strategy.engine.history.HistoryNode;
@@ -167,7 +168,8 @@ private void createAndSaveStats(final boolean showPhaseStats) {
try (PrintWriter writer =
new PrintWriter(chooser.getSelectedFile(), StandardCharsets.UTF_8.toString())) {
gameData.acquireReadLock();
- final GameData clone = GameDataUtils.cloneGameData(gameData).orElse(null);
+ final var cloneOptions = GameDataManager.Options.builder().withHistory(true).build();
+ final GameData clone = GameDataUtils.cloneGameData(gameData, cloneOptions).orElse(null);
if (clone == null) {
return;
}
@@ -394,7 +396,8 @@ private void exportSetupCharts() {
final GameData clonedGameData;
gameData.acquireReadLock();
try {
- clonedGameData = GameDataUtils.cloneGameData(gameData).orElse(null);
+ final var cloneOptions = GameDataManager.Options.builder().withHistory(true).build();
+ clonedGameData = GameDataUtils.cloneGameData(gameData, cloneOptions).orElse(null);
if (clonedGameData == null) {
return;
}