Added json summary generation after replay is compiled.

This commit is contained in:
Christian 'ketura' McCarty
2023-03-17 01:33:25 -05:00
parent 40dd23da93
commit 9478b9aefd
5 changed files with 175 additions and 9 deletions

View File

@@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSON;
import com.gempukku.lotro.async.HttpProcessingException;
import com.gempukku.lotro.async.ResponseWriter;
import com.gempukku.lotro.game.Player;
import com.google.gson.Gson;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;
@@ -14,7 +13,6 @@ import java.lang.reflect.Type;
import java.util.Map;
public class PlayerInfoRequestHandler extends LotroServerRequestHandler implements UriRequestHandler {
private final Gson JsonConvert = new Gson();
private static final Logger _log = Logger.getLogger(PlayerInfoRequestHandler.class);

View File

@@ -16,10 +16,7 @@ public class EventSerializer {
public Node serializeEvent(Document doc, GameEvent gameEvent) {
Element eventElem = doc.createElement("ge");
eventElem.setAttribute("type", gameEvent.getType().getCode());
//TODO:
// - figure out a better date/time format for the log
// - import the json replay info into gemp
eventElem.setAttribute("timestamp", gameEvent.getTimestamp().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
eventElem.setAttribute("timestamp", gameEvent.getTimestamp().format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss.SSSS")));
if (gameEvent.getBlueprintId() != null)
eventElem.setAttribute("blueprintId", gameEvent.getBlueprintId());

View File

@@ -18,6 +18,7 @@ import java.util.Objects;
public class DbGameHistoryDAO implements GameHistoryDAO {
private final DbAccess _dbAccess;
private final DateTimeFormatter _dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private final DateTimeFormatter _dateTimeFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
public DbGameHistoryDAO(DbAccess dbAccess) {
_dbAccess = dbAccess;
@@ -49,8 +50,8 @@ public class DbGameHistoryDAO implements GameHistoryDAO {
.addParameter("tournament", tournament)
.addParameter("winner_deck_name", winnerDeckName)
.addParameter("loser_deck_name", loserDeckName)
.addParameter("start_date", startDate.format(DateTimeFormatter.ISO_DATE_TIME))
.addParameter("end_date", endDate.format(DateTimeFormatter.ISO_DATE_TIME))
.addParameter("start_date", startDate.format(_dateTimeFormat))
.addParameter("end_date", endDate.format(_dateTimeFormat))
.addParameter("version", replayVersion);
query.executeUpdate();

View File

@@ -1,5 +1,6 @@
package com.gempukku.lotro.game;
import com.alibaba.fastjson.JSON;
import com.gempukku.lotro.common.AppConfig;
import com.gempukku.lotro.common.DBDefs;
import com.gempukku.lotro.db.PlayerDAO;
@@ -114,6 +115,16 @@ public class GameRecorder {
return new File(playerReplayFolder, gameId + ".xml.gz");
}
private File getSummaryFile(DBDefs.GameHistory history) {
var gameReplayFolder = new File(AppConfig.getProperty("application.root"), "replay");
var summaryFolder = new File(gameReplayFolder, "summaries");
var yearFolder = new File(summaryFolder, String.format("%04d", history.start_date.getYear()));
var monthFolder = new File(yearFolder, String.format("%02d", history.start_date.getMonthValue()));
monthFolder.mkdirs();
return new File(monthFolder, history.winner + "_vs_" + history.loser + "_" +
history.win_recording_id + "_" + history.lose_recording_id+ ".json");
}
private OutputStream getRecordingWriteStream(String playerId, String gameId, ZonedDateTime startDate) throws IOException {
File recordingFile = getRecordingFileVersion1(playerId, gameId, startDate);
recordingFile.getParentFile().mkdirs();
@@ -124,6 +135,8 @@ public class GameRecorder {
private Map<String, String> saveRecordedChannels(Map<String, GameCommunicationChannel> gameProgress, DBDefs.GameHistory gameInfo, Map<String, LotroDeck> decks) {
Map<String, String> result = new HashMap<>();
var metadata = new ReplayMetadata(gameInfo, decks);
for (Map.Entry<String, GameCommunicationChannel> playerRecordings : gameProgress.entrySet()) {
String playerId = playerRecordings.getKey();
String recordingId = "";
@@ -135,6 +148,7 @@ public class GameRecorder {
}
final List<GameEvent> gameEvents = playerRecordings.getValue().consumeGameEvents();
metadata.ParseReplay(playerId, gameEvents);
try {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
@@ -187,10 +201,15 @@ public class GameRecorder {
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(source, streamResult);
}
result.put(playerId, recordingId);
try(var out = new PrintWriter(getSummaryFile(gameInfo).getAbsolutePath())) {
out.println(JSON.toJSONString(metadata));
}
} catch (Exception exp) {
}
result.put(playerId, recordingId);
}
return result;
}

View File

@@ -0,0 +1,151 @@
package com.gempukku.lotro.game;
import com.gempukku.lotro.common.DBDefs;
import com.gempukku.lotro.common.Zone;
import com.gempukku.lotro.game.state.GameEvent;
import com.gempukku.lotro.logic.vo.LotroDeck;
import com.mysql.cj.util.StringUtils;
import java.util.*;
import java.util.regex.Pattern;
public class ReplayMetadata {
public class DeckMetadata {
public String Owner;
public String TargetFormat;
public String DeckName;
public List<String> AdventureDeck;
public List<String> DrawDeck;
public String RingBearer;
public String Ring;
public List<String> StartingFellowship = new ArrayList<>();
}
public Integer MetadataVersion = 1;
public DBDefs.GameHistory GameReplayInfo;
public Map<String, DeckMetadata> Decks = new HashMap<>();
public Map<String, Integer> PlayerIDs = new HashMap<>();
public Map<String, Integer> Bids = new HashMap<>();
public String WentFirst;
public boolean GameStarted = false;
public boolean Conceded = false;
public boolean Canceled = false;
public Map<String, String> AllCards = new HashMap<>();
public Set<Integer> SeenCards = new HashSet<>();
public HashSet<Integer> PlayedCards = new HashSet<>();
public ReplayMetadata(DBDefs.GameHistory game, Map<String, LotroDeck> decks) {
GameReplayInfo = game;
for(var pair : decks.entrySet()) {
String player = pair.getKey();
var deck = pair.getValue();
var metadata = new DeckMetadata() {{
Owner = player;
TargetFormat = deck.getTargetFormat();
DeckName = deck.getDeckName();
AdventureDeck = deck.getSites();
DrawDeck = deck.getAdventureCards();
RingBearer = deck.getRingBearer();
Ring = deck.getRing();
}};
Decks.put(player, metadata);
}
if(GameReplayInfo.lose_reason.contains("cancelled") || GameReplayInfo.win_reason.contains("cancelled")) {
Canceled = true;
}
if(GameReplayInfo.lose_reason.contains("Concession") || GameReplayInfo.win_reason.contains("Concession")) {
Conceded = true;
}
}
public String GetOpponent(String player) {
return PlayerIDs.keySet().stream().filter(x -> !x.equals(player)).findFirst().get();
}
private final Pattern gameStartPattern = Pattern.compile("Players in the game are: ([\\w-]+), ([\\w-]+)");
private final Pattern orderPattern = Pattern.compile("([\\w-]+) has chosen to go (.*)");
private final Pattern bidPattern = Pattern.compile("([\\w-]+) bid (\\d+)");
public void ParseReplay(String player, List<GameEvent> events) {
GameStarted = false;
for(var event : events) {
if(event.getType() == GameEvent.Type.SEND_MESSAGE) {
var message = event.getMessage();
if(StringUtils.isNullOrEmpty(message))
continue;
var regex = gameStartPattern.matcher(message);
if(regex.matches()) {
PlayerIDs.put(regex.group(1), 1);
PlayerIDs.put(regex.group(2), 2);
continue;
}
regex = orderPattern.matcher(message);
if(regex.matches()) {
String bidder = regex.group(1);
String order = regex.group(2);
if(order.equals("first")) {
WentFirst = bidder;
}
else if(order.equals("second")) {
WentFirst = GetOpponent(bidder);
}
continue;
}
regex = bidPattern.matcher(message);
if(regex.matches()) {
String bidder = regex.group(1);
String bid = regex.group(2);
Bids.put(bidder, Integer.valueOf(bid));
continue;
}
}
else if(!GameStarted && event.getType() == GameEvent.Type.GAME_PHASE_CHANGE) {
var phase = event.getPhase();
if (phase != null && phase.equals("Between turns"))
{
GameStarted = true;
}
}
else if(event.getType() == GameEvent.Type.PUT_CARD_INTO_PLAY) {
var bpID = event.getBlueprintId();
var cardID = event.getCardId();
var participantID = event.getParticipantId();
var zone = event.getZone();
var targetCardID = event.getTargetCardId();
if (bpID != null && cardID != null && participantID != null && participantID.equals(player)) {
if (!GameStarted && (zone.equals(Zone.FREE_CHARACTERS)) || zone.equals(Zone.ATTACHED)) {
Decks.get(player).StartingFellowship.add(bpID);
}
switch (zone) {
case FREE_CHARACTERS, SUPPORT, SHADOW_CHARACTERS, ADVENTURE_PATH, VOID_FROM_HAND, VOID -> {
AllCards.put(cardID.toString(), bpID);
SeenCards.add(cardID);
PlayedCards.add(cardID);
}
case ATTACHED, HAND, STACKED, DEAD, DISCARD, ADVENTURE_DECK, DECK, REMOVED -> {
AllCards.put(cardID.toString(), bpID);
SeenCards.add(cardID);
}
}
}
}
}
}
}