diff --git a/.gitignore b/.gitignore
index 92368d784d..2b2ae770ee 100644
--- a/.gitignore
+++ b/.gitignore
@@ -135,3 +135,4 @@ client_secrets.json
dependency-reduced-pom.xml
mage-bundle
+/Mage.Client/game-*.json
diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml
index db453f4cd3..40fcfe1b91 100644
--- a/Mage.Client/pom.xml
+++ b/Mage.Client/pom.xml
@@ -15,6 +15,7 @@
Mage Client
+
org.mage
mage
@@ -68,6 +69,11 @@
jetlang
0.2.9
+
+ com.amazonaws
+ aws-java-sdk-s3
+ 1.11.286
+
com.jgoodies
forms
diff --git a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java
index 386c2156a6..f16b0bee0e 100644
--- a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java
+++ b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java
@@ -31,7 +31,11 @@ import java.awt.event.KeyEvent;
import java.util.List;
import java.util.UUID;
import javax.swing.*;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
import mage.cards.decks.Deck;
+import mage.client.remote.S3Uploader;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.chat.ChatPanelBasic;
@@ -47,6 +51,9 @@ import mage.client.util.audio.AudioManager;
import mage.client.util.object.SaveObjectUtil;
import mage.interfaces.callback.CallbackClient;
import mage.interfaces.callback.ClientCallback;
+import mage.remote.ActionData;
+import mage.remote.Session;
+import mage.remote.SessionImpl;
import mage.utils.CompressUtil;
import mage.view.*;
import mage.view.ChatMessage.MessageType;
@@ -102,7 +109,6 @@ public class CallbackClientImpl implements CallbackClient {
break;
case CHATMESSAGE: {
ChatMessage message = (ChatMessage) callback.getData();
-
// Drop messages from ignored users
if (message.getUsername() != null && IgnoreList.IGNORED_MESSAGE_TYPES.contains(message.getMessageType())) {
final String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
@@ -183,13 +189,22 @@ public class CallbackClientImpl implements CallbackClient {
case GAME_INIT: {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
+ appendJsonEvent("GAME_INIT", callback.getObjectId(), (GameView) callback.getData());
panel.init((GameView) callback.getData());
}
break;
}
case GAME_OVER: {
+
GamePanel panel = MageFrame.getGame(callback.getObjectId());
+
if (panel != null) {
+ appendJsonEvent("GAME_OVER", callback.getObjectId(), callback.getData());
+ ActionData actionData = appendJsonEvent("GAME_OVER", callback.getObjectId(), callback.getData());
+ String logFileName = "game-" + actionData.gameId + ".json";
+
+ S3Uploader.upload(logFileName, actionData.gameId.toString());
+
panel.endMessage((String) callback.getData(), callback.getMessageId());
}
break;
@@ -201,6 +216,7 @@ public class CallbackClientImpl implements CallbackClient {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
+ appendJsonEvent("GAME_ASK", callback.getObjectId(), message);
panel.ask(message.getMessage(), message.getGameView(), callback.getMessageId(), message.getOptions());
}
break;
@@ -208,8 +224,10 @@ public class CallbackClientImpl implements CallbackClient {
case GAME_TARGET: // e.g. Pick triggered ability
{
GameClientMessage message = (GameClientMessage) callback.getData();
+
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
+ appendJsonEvent("GAME_TARGET", callback.getObjectId(), message);
panel.pickTarget(message.getMessage(), message.getCardsView(), message.getGameView(),
message.getTargets(), message.isFlag(), message.getOptions(), callback.getMessageId());
}
@@ -217,8 +235,10 @@ public class CallbackClientImpl implements CallbackClient {
}
case GAME_SELECT: {
GameClientMessage message = (GameClientMessage) callback.getData();
+
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
+ appendJsonEvent("GAME_SELECT", callback.getObjectId(), message);
panel.select(message.getMessage(), message.getGameView(), callback.getMessageId(), message.getOptions());
}
break;
@@ -226,6 +246,7 @@ public class CallbackClientImpl implements CallbackClient {
case GAME_CHOOSE_ABILITY: {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
+ appendJsonEvent("GAME_CHOOSE_PILE", callback.getObjectId(), callback.getData());
panel.pickAbility((AbilityPickerView) callback.getData());
}
break;
@@ -234,15 +255,18 @@ public class CallbackClientImpl implements CallbackClient {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
+ appendJsonEvent("GAME_CHOOSE_PILE", callback.getObjectId(), message);
panel.pickPile(message.getMessage(), message.getPile1(), message.getPile2());
}
break;
}
case GAME_CHOOSE_CHOICE: {
GameClientMessage message = (GameClientMessage) callback.getData();
+
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
+ appendJsonEvent("GAME_CHOOSE_CHOICE", callback.getObjectId(), message);
panel.getChoice(message.getChoice(), callback.getObjectId());
}
break;
@@ -251,35 +275,45 @@ public class CallbackClientImpl implements CallbackClient {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
+ appendJsonEvent("GAME_PLAY_MANA", callback.getObjectId(), message);
panel.playMana(message.getMessage(), message.getGameView(), message.getOptions(), callback.getMessageId());
}
break;
}
case GAME_PLAY_XMANA: {
GameClientMessage message = (GameClientMessage) callback.getData();
+
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
+ appendJsonEvent("GAME_PLAY_XMANA", callback.getObjectId(), message);
panel.playXMana(message.getMessage(), message.getGameView(), callback.getMessageId());
}
break;
}
case GAME_GET_AMOUNT: {
GameClientMessage message = (GameClientMessage) callback.getData();
+
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
+ appendJsonEvent("GAME_GET_AMOUNT", callback.getObjectId(), message);
+
panel.getAmount(message.getMin(), message.getMax(), message.getMessage());
}
break;
}
case GAME_UPDATE: {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
+
if (panel != null) {
+ appendJsonEvent("GAME_UPDATE", callback.getObjectId(), callback.getData());
+
panel.updateGame((GameView) callback.getData());
}
break;
}
case END_GAME_INFO:
MageFrame.getInstance().showGameEndDialog((GameEndView) callback.getData());
+
break;
case SHOW_USERMESSAGE:
List messageData = (List) callback.getData();
@@ -293,6 +327,7 @@ public class CallbackClientImpl implements CallbackClient {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
+ appendJsonEvent("GAME_INFORM", callback.getObjectId(), message);
panel.inform(message.getMessage(), message.getGameView(), callback.getMessageId());
}
}
@@ -375,7 +410,13 @@ public class CallbackClientImpl implements CallbackClient {
}
});
}
-
+ private ActionData appendJsonEvent(String name, UUID gameId, Object value) {
+ Session session = SessionHandler.getSession();
+ ActionData actionData = new ActionData(name, gameId);
+ actionData.value = value;
+ session.appendJsonLog(actionData);
+ return actionData;
+ }
private void createChatStartMessage(ChatPanelBasic chatPanel) {
chatPanel.setStartMessageDone(true);
ChatPanelBasic usedPanel = chatPanel;
diff --git a/Mage.Client/src/main/java/mage/client/remote/S3Uploader.java b/Mage.Client/src/main/java/mage/client/remote/S3Uploader.java
new file mode 100644
index 0000000000..21e9504f41
--- /dev/null
+++ b/Mage.Client/src/main/java/mage/client/remote/S3Uploader.java
@@ -0,0 +1,47 @@
+package mage.client.remote;
+
+import java.io.File;
+
+import com.amazonaws.AmazonClientException;
+import com.amazonaws.auth.BasicAWSCredentials;
+import com.amazonaws.services.s3.transfer.TransferManager;
+import com.amazonaws.services.s3.transfer.Upload;
+import org.apache.log4j.Logger;
+
+import javax.xml.crypto.Data;
+
+
+public class S3Uploader {
+ private static final Logger logger = Logger.getLogger(S3Uploader.class);
+
+ public static Boolean upload(String filePath, String keyName) throws Exception {
+ String existingBucketName = System.getenv("S3_BUCKET") != null ? System.getenv("S3_BUCKET")
+ : "xmage-game-logs-dev";
+
+ String accessKeyId = System.getenv("AWS_ACCESS_ID");
+ String secretKeyId = System.getenv("AWS_SECRET_KEY");
+
+ if(accessKeyId == "" || secretKeyId == "" || existingBucketName == "") {
+ logger.info("Aborting json log sync.");
+ return false;
+ }
+
+ String path = new File("./" + filePath).getCanonicalPath();
+ logger.info("Syncing " + path + " to bucket: " + existingBucketName + " with AWS Access Id: " + accessKeyId);
+
+ BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKeyId, secretKeyId);
+ TransferManager tm = new TransferManager(awsCreds);
+ Upload upload = tm.upload(existingBucketName, "/game/" + keyName + ".json", new File(path));
+
+ try {
+ upload.waitForUploadResult();
+ logger.info("Sync Complete For " + path + " to bucket: " + existingBucketName + " with AWS Access Id: " + accessKeyId);
+ new File(path);
+ return true;
+ } catch (AmazonClientException amazonClientException) {
+ System.out.println("Unable to upload file, upload was aborted.");
+ amazonClientException.printStackTrace();
+ return false;
+ }
+ }
+}
diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml
index 27914c196d..17075941d0 100644
--- a/Mage.Common/pom.xml
+++ b/Mage.Common/pom.xml
@@ -25,6 +25,7 @@
jspf-core
0.9.1
+
org.jboss.remoting
jboss-remoting
@@ -50,7 +51,11 @@
trove
1.0.2
-
+
+ com.google.code.gson
+ gson
+ 2.8.2
+
diff --git a/Mage.Common/src/main/java/mage/remote/ActionData.java b/Mage.Common/src/main/java/mage/remote/ActionData.java
new file mode 100644
index 0000000000..d173535b14
--- /dev/null
+++ b/Mage.Common/src/main/java/mage/remote/ActionData.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2018 nanarpuss_at_googlemail.com. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of BetaSteward_at_googlemail.com.
+ */
+
+package mage.remote;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import mage.remote.interfaces.*;
+
+import java.util.UUID;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.ExclusionStrategy;
+import com.google.gson.FieldAttributes;
+
+public class ActionData {
+ @Expose
+ public UUID gameId;
+ @Expose
+ public String sessionId;
+ @Expose
+ public String type;
+ @Expose
+ public Object value;
+ @Expose
+ public String message;
+
+ public String toJson() {
+ GsonBuilder gsonBuilder = new GsonBuilder();
+ Gson gson = gsonBuilder.setExclusionStrategies(new CustomExclusionStrategy()).create();
+
+ return gson.toJson(this);
+ }
+
+ public ActionData(String type, UUID gameId, String sessionId) {
+ this.type = type;
+ this.sessionId = sessionId;
+ this.gameId = gameId;
+ }
+
+ public ActionData(String type, UUID gameId) {
+ this.type = type;
+ this.gameId = gameId;
+ }
+
+ public class CustomExclusionStrategy implements ExclusionStrategy {
+ // FIXME: Very crude way of whitelisting, as it applies to all levels of the JSON tree.
+ private final java.util.Set KEEP = new java.util.HashSet(
+ java.util.Arrays.asList(
+ new String[]{
+ "id",
+ "choice",
+ "damage",
+ "abilityType",
+ "ability",
+ "abilities",
+ "method",
+ "data",
+ "options",
+ "life",
+ "players",
+ "zone",
+ "step",
+ "phase",
+ "attackers",
+ "blockers",
+ "tapped",
+ "damage",
+ "combat",
+ "paid",
+ "hand",
+ "stack",
+ "convertedManaCost",
+ "gameId",
+ "canPlayInHand",
+ "gameView",
+ "sessionId",
+ "power",
+ "choices",
+ "targets",
+ "loyalty",
+ "toughness",
+ "power",
+ "type",
+ "priorityTime",
+ "manaCost",
+ "value",
+ "message",
+ "cardsView",
+ "name",
+ "count",
+ "counters",
+ "battlefield",
+ "parentId"
+ }));
+
+ public CustomExclusionStrategy() {}
+
+ // This method is called for all fields. if the method returns true the
+ // field is excluded from serialization
+ @Override
+ public boolean shouldSkipField(FieldAttributes f) {
+ String name = f.getName();
+ return !KEEP.contains(name);
+ }
+
+ // This method is called for all classes. If the method returns true the
+ // class is excluded.
+ @Override
+ public boolean shouldSkipClass(Class> clazz) {
+ return false;
+ }
+ }
+}
diff --git a/Mage.Common/src/main/java/mage/remote/Session.java b/Mage.Common/src/main/java/mage/remote/Session.java
index 8cb062c63e..67022d59e8 100644
--- a/Mage.Common/src/main/java/mage/remote/Session.java
+++ b/Mage.Common/src/main/java/mage/remote/Session.java
@@ -38,6 +38,7 @@ import mage.remote.interfaces.PlayerActions;
import mage.remote.interfaces.Replays;
import mage.remote.interfaces.ServerState;
import mage.remote.interfaces.Testable;
+import mage.remote.ActionData;
/**
* Extracted interface for SessionImpl class.
@@ -45,5 +46,5 @@ import mage.remote.interfaces.Testable;
* @author noxx
*/
public interface Session extends ClientData, Connect, GamePlay, GameTypes, ServerState, ChatSession, Feedback, PlayerActions, Replays, Testable {
-
+ public void appendJsonLog(ActionData actionData);
}
diff --git a/Mage.Common/src/main/java/mage/remote/SessionImpl.java b/Mage.Common/src/main/java/mage/remote/SessionImpl.java
index 1f7bca2c0c..907de603b0 100644
--- a/Mage.Common/src/main/java/mage/remote/SessionImpl.java
+++ b/Mage.Common/src/main/java/mage/remote/SessionImpl.java
@@ -32,6 +32,11 @@ import java.lang.reflect.UndeclaredThrowableException;
import java.net.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
+import java.io.BufferedWriter;
+import java.io.PrintWriter;
+import java.io.FileWriter;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
import mage.MageException;
import mage.cards.decks.DeckCardLists;
import mage.cards.repository.CardInfo;
@@ -50,6 +55,7 @@ import mage.interfaces.callback.ClientCallback;
import mage.players.PlayerType;
import mage.players.net.UserData;
import mage.utils.CompressUtil;
+import mage.remote.ActionData;
import mage.view.*;
import org.apache.log4j.Logger;
import org.jboss.remoting.*;
@@ -798,6 +804,9 @@ public class SessionImpl implements Session {
public boolean sendPlayerUUID(UUID gameId, UUID data) {
try {
if (isConnected()) {
+ ActionData actionData = new ActionData("SEND_PLAYER_UUID", gameId, getSessionId());
+ actionData.value = data;
+ appendJsonLog(actionData);
server.sendPlayerUUID(gameId, sessionId, data);
return true;
}
@@ -813,6 +822,10 @@ public class SessionImpl implements Session {
public boolean sendPlayerBoolean(UUID gameId, boolean data) {
try {
if (isConnected()) {
+ ActionData actionData = new ActionData("SEND_PLAYER_BOOLEAN", gameId, getSessionId());
+ actionData.value = data;
+ appendJsonLog(actionData);
+
server.sendPlayerBoolean(gameId, sessionId, data);
return true;
}
@@ -828,6 +841,10 @@ public class SessionImpl implements Session {
public boolean sendPlayerInteger(UUID gameId, int data) {
try {
if (isConnected()) {
+ ActionData actionData = new ActionData("SEND_PLAYER_INTEGER", gameId, getSessionId());
+ actionData.value = data;
+ appendJsonLog(actionData);
+
server.sendPlayerInteger(gameId, sessionId, data);
return true;
}
@@ -843,6 +860,10 @@ public class SessionImpl implements Session {
public boolean sendPlayerString(UUID gameId, String data) {
try {
if (isConnected()) {
+ ActionData actionData = new ActionData("SEND_PLAYER_STRING", gameId, getSessionId());
+ actionData.value = data;
+ appendJsonLog(actionData);
+
server.sendPlayerString(gameId, sessionId, data);
return true;
}
@@ -858,6 +879,9 @@ public class SessionImpl implements Session {
public boolean sendPlayerManaType(UUID gameId, UUID playerId, ManaType data) {
try {
if (isConnected()) {
+ ActionData actionData = new ActionData("SEND_PLAYER_MANA_TYPE", gameId, getSessionId());
+ actionData.value = data;
+ appendJsonLog(actionData);
server.sendPlayerManaType(gameId, playerId, sessionId, data);
return true;
}
@@ -869,6 +893,19 @@ public class SessionImpl implements Session {
return false;
}
+ @Override
+ public void appendJsonLog(ActionData actionData) {
+ actionData.sessionId = getSessionId();
+
+ String logFileName = "game-" + actionData.gameId + ".json";
+ System.out.println("Logging to " + logFileName);
+ try(PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(logFileName, true)))) {
+ out.println(actionData.toJson());
+ } catch (IOException e) {
+ System.err.println(e);
+ }
+ }
+
@Override
public DraftPickView sendCardPick(UUID draftId, UUID cardId, Set hiddenCards) {
try {
@@ -1274,6 +1311,11 @@ public class SessionImpl implements Session {
public boolean sendPlayerAction(PlayerAction passPriorityAction, UUID gameId, Object data) {
try {
if (isConnected()) {
+ ActionData actionData = new ActionData("SEND_PLAYER_ACTION", gameId, getSessionId());
+
+ actionData.value = data;
+ appendJsonLog(actionData);
+
server.sendPlayerAction(passPriorityAction, gameId, sessionId, data);
return true;
}
diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java
index d9154f7418..b2ed194eb8 100644
--- a/Mage.Common/src/main/java/mage/view/CardView.java
+++ b/Mage.Common/src/main/java/mage/view/CardView.java
@@ -53,6 +53,8 @@ import mage.target.Target;
import mage.target.Targets;
import mage.util.SubTypeList;
+import com.google.gson.annotations.Expose;
+
/**
* @author BetaSteward_at_googlemail.com
*/
@@ -61,11 +63,17 @@ public class CardView extends SimpleCardView {
private static final long serialVersionUID = 1L;
protected UUID parentId;
+ @Expose
protected String name;
+ @Expose
protected String displayName;
+ @Expose
protected List rules;
+ @Expose
protected String power;
+ @Expose
protected String toughness;
+ @Expose
protected String loyalty = "";
protected String startingLoyalty;
protected EnumSet cardTypes;
@@ -110,7 +118,6 @@ public class CardView extends SimpleCardView {
protected ArtRect artRect = ArtRect.NORMAL;
protected List targets;
-
protected UUID pairedCard;
protected List bandedCards;
protected boolean paid;
diff --git a/Mage.Common/src/main/java/mage/view/GameClientMessage.java b/Mage.Common/src/main/java/mage/view/GameClientMessage.java
index 33af5e25e9..1774c766f9 100644
--- a/Mage.Common/src/main/java/mage/view/GameClientMessage.java
+++ b/Mage.Common/src/main/java/mage/view/GameClientMessage.java
@@ -32,6 +32,11 @@ import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.annotations.Expose;
+
import mage.choices.Choice;
/**
@@ -39,18 +44,29 @@ import mage.choices.Choice;
* @author BetaSteward_at_googlemail.com
*/
public class GameClientMessage implements Serializable {
+ @Expose
private static final long serialVersionUID = 1L;
-
+ @Expose
private GameView gameView;
+ @Expose
private CardsView cardsView;
+ @Expose
private CardsView cardsView2;
+ @Expose
private String message;
+ @Expose
private boolean flag;
+ @Expose
private String[] strings;
+ @Expose
private Set targets;
+ @Expose
private int min;
+ @Expose
private int max;
+ @Expose
private Map options;
+ @Expose
private Choice choice;
public GameClientMessage(GameView gameView) {
@@ -155,4 +171,11 @@ public class GameClientMessage implements Serializable {
return choice;
}
+ public String toJson() {
+ Gson gson = new GsonBuilder()
+ .excludeFieldsWithoutExposeAnnotation()
+ .create();
+ return gson.toJson(this);
+ }
+
}
diff --git a/Mage.Common/src/main/java/mage/view/GameView.java b/Mage.Common/src/main/java/mage/view/GameView.java
index 2e16415ad6..b354503c56 100644
--- a/Mage.Common/src/main/java/mage/view/GameView.java
+++ b/Mage.Common/src/main/java/mage/view/GameView.java
@@ -28,11 +28,17 @@
package mage.view;
import java.io.Serializable;
+import java.io.BufferedWriter;
+import java.io.PrintWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+
import mage.MageObject;
import mage.abilities.costs.Cost;
import mage.cards.Card;
@@ -54,6 +60,8 @@ import mage.game.stack.StackObject;
import mage.players.Player;
import mage.watchers.common.CastSpellLastTurnWatcher;
import org.apache.log4j.Logger;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
/**
*
@@ -64,7 +72,6 @@ public class GameView implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(GameView.class);
-
private final int priorityTime;
private final List players = new ArrayList<>();
private CardsView hand;
@@ -351,4 +358,8 @@ public class GameView implements Serializable {
return rollbackTurnsAllowed;
}
+ public String toJson() {
+ Gson gson = new GsonBuilder().create();
+ return gson.toJson(this);
+ }
}
diff --git a/Mage.Common/src/main/java/mage/view/SimpleCardView.java b/Mage.Common/src/main/java/mage/view/SimpleCardView.java
index 709e45ad83..a137f0ca0e 100644
--- a/Mage.Common/src/main/java/mage/view/SimpleCardView.java
+++ b/Mage.Common/src/main/java/mage/view/SimpleCardView.java
@@ -28,6 +28,8 @@
package mage.view;
+import com.google.gson.annotations.Expose;
+
import java.io.Serializable;
import java.util.UUID;
@@ -36,6 +38,7 @@ import java.util.UUID;
* @author BetaSteward_at_googlemail.com
*/
public class SimpleCardView implements Serializable {
+ @Expose
protected UUID id;
protected String expansionSetCode;
protected String tokenSetCode;
diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml
index f756f0f7c1..20899230cc 100644
--- a/Mage.Server/pom.xml
+++ b/Mage.Server/pom.xml
@@ -76,6 +76,12 @@
${project.version}
runtime
+
+ org.apache.commons
+ commons-compress
+ 1.16.1
+
+
${project.groupId}
mage-game-commanderfreeforall