forked from External/mage
Record game histories. Compute user stats and show them in the user panel.
This commit is contained in:
parent
9f3e2aa4c4
commit
550648ccbe
22 changed files with 866 additions and 60 deletions
|
|
@ -438,7 +438,7 @@ public class MageServerImpl implements MageServer {
|
|||
// }
|
||||
@Override
|
||||
public boolean startMatch(final String sessionId, final UUID roomId, final UUID tableId) throws MageException {
|
||||
if (!TableManager.getInstance().getController(tableId).changeTableState(TableState.STARTING)) {
|
||||
if (!TableManager.getInstance().getController(tableId).changeTableStateToStarting()) {
|
||||
return false;
|
||||
}
|
||||
execute("startMatch", sessionId, new Action() {
|
||||
|
|
@ -463,7 +463,7 @@ public class MageServerImpl implements MageServer {
|
|||
// }
|
||||
@Override
|
||||
public boolean startTournament(final String sessionId, final UUID roomId, final UUID tableId) throws MageException {
|
||||
if (!TableManager.getInstance().getController(tableId).changeTableState(TableState.STARTING)) {
|
||||
if (!TableManager.getInstance().getController(tableId).changeTableStateToStarting()) {
|
||||
return false;
|
||||
}
|
||||
execute("startTournament", sessionId, new Action() {
|
||||
|
|
|
|||
|
|
@ -32,10 +32,20 @@ import java.io.FilenameFilter;
|
|||
import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.management.MBeanServer;
|
||||
import mage.cards.repository.CardScanner;
|
||||
import mage.game.match.MatchType;
|
||||
import mage.game.result.ResultProtos.MatchPlayerProto;
|
||||
import mage.game.result.ResultProtos.MatchProto;
|
||||
import mage.game.result.ResultProtos.TableProto;
|
||||
import mage.game.result.ResultProtos.TourneyPlayerProto;
|
||||
import mage.game.result.ResultProtos.TourneyProto;
|
||||
import mage.game.result.ResultProtos.UserStatsProto;
|
||||
import mage.game.tournament.TournamentType;
|
||||
import mage.interfaces.MageServer;
|
||||
import mage.remote.Connection;
|
||||
|
|
@ -43,6 +53,10 @@ import mage.server.draft.CubeFactory;
|
|||
import mage.server.game.DeckValidatorFactory;
|
||||
import mage.server.game.GameFactory;
|
||||
import mage.server.game.PlayerFactory;
|
||||
import mage.server.record.TableRecord;
|
||||
import mage.server.record.TableRecordRepository;
|
||||
import mage.server.record.UserStats;
|
||||
import mage.server.record.UserStatsRepository;
|
||||
import mage.server.tournament.TournamentFactory;
|
||||
import mage.server.util.ConfigSettings;
|
||||
import mage.server.util.PluginClassLoader;
|
||||
|
|
@ -88,6 +102,8 @@ public class Main {
|
|||
protected static boolean testMode;
|
||||
protected static boolean fastDbMode;
|
||||
|
||||
private static final ScheduledExecutorService updateUserStatsTaskExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
|
|
@ -174,6 +190,13 @@ public class Main {
|
|||
} catch (Exception ex) {
|
||||
logger.fatal("Failed to start server - " + connection.toString(), ex);
|
||||
}
|
||||
|
||||
updateUserStatsTaskExecutor.scheduleAtFixedRate(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateUserStats();
|
||||
}
|
||||
}, 60, 60, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
static void initStatistics() {
|
||||
|
|
@ -368,4 +391,68 @@ public class Main {
|
|||
public static boolean isTestMode() {
|
||||
return testMode;
|
||||
}
|
||||
|
||||
private static void updateUserStats() {
|
||||
long latestEndTimeMs = UserStatsRepository.instance.getLatestEndTimeMs();
|
||||
List<TableRecord> records = TableRecordRepository.instance.getAfter(latestEndTimeMs);
|
||||
for (TableRecord record : records) {
|
||||
TableProto table = record.getProto();
|
||||
if (table.getControllerName().equals("System")) {
|
||||
// This is a sub table within a tournament, so it's already handled by the main
|
||||
// tournament table.
|
||||
continue;
|
||||
}
|
||||
if (table.hasMatch()) {
|
||||
MatchProto match = table.getMatch();
|
||||
for (MatchPlayerProto player : match.getPlayersList()) {
|
||||
UserStats userStats = UserStatsRepository.instance.getUser(player.getName());
|
||||
UserStatsProto proto = userStats != null ? userStats.getProto() :
|
||||
UserStatsProto.newBuilder().setName(player.getName()).build();
|
||||
UserStatsProto.Builder builder = UserStatsProto.newBuilder(proto)
|
||||
.setMatches(proto.getMatches() + 1);
|
||||
switch (player.getQuit()) {
|
||||
case IDLE_TIMEOUT:
|
||||
builder.setMatchesIdleTimeout(proto.getMatchesIdleTimeout() + 1);
|
||||
break;
|
||||
case TIMER_TIMEOUT:
|
||||
builder.setMatchesTimerTimeout(proto.getMatchesTimerTimeout() + 1);
|
||||
break;
|
||||
case QUIT:
|
||||
builder.setMatchesQuit(proto.getMatchesQuit() + 1);
|
||||
break;
|
||||
}
|
||||
if (userStats == null) {
|
||||
UserStatsRepository.instance.add(new UserStats(builder.build(), table.getEndTimeMs()));
|
||||
} else {
|
||||
UserStatsRepository.instance.update(new UserStats(builder.build(), table.getEndTimeMs()));
|
||||
}
|
||||
}
|
||||
} else if (table.hasTourney()) {
|
||||
TourneyProto tourney = table.getTourney();
|
||||
for (TourneyPlayerProto player : tourney.getPlayersList()) {
|
||||
UserStats userStats = UserStatsRepository.instance.getUser(player.getName());
|
||||
UserStatsProto proto = userStats != null ? userStats.getProto() :
|
||||
UserStatsProto.newBuilder().setName(player.getName()).build();
|
||||
UserStatsProto.Builder builder = UserStatsProto.newBuilder(proto)
|
||||
.setTourneys(proto.getTourneys() + 1);
|
||||
switch (player.getQuit()) {
|
||||
case DURING_ROUND:
|
||||
builder.setTourneysQuitDuringRound(proto.getTourneysQuitDuringRound() + 1);
|
||||
break;
|
||||
case DURING_DRAFTING:
|
||||
builder.setTourneysQuitDuringDrafting(proto.getTourneysQuitDuringDrafting() + 1);
|
||||
break;
|
||||
case DURING_CONSTRUCTION:
|
||||
builder.setTourneysQuitDuringConstruction(proto.getTourneysQuitDuringConstruction() + 1);
|
||||
break;
|
||||
}
|
||||
if (userStats == null) {
|
||||
UserStatsRepository.instance.add(new UserStats(builder.build(), table.getEndTimeMs()));
|
||||
} else {
|
||||
UserStatsRepository.instance.update(new UserStats(builder.build(), table.getEndTimeMs()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ import mage.server.game.DeckValidatorFactory;
|
|||
import mage.server.game.GameFactory;
|
||||
import mage.server.game.GameManager;
|
||||
import mage.server.game.PlayerFactory;
|
||||
import mage.server.record.TableRecorderImpl;
|
||||
import mage.server.services.LogKeys;
|
||||
import mage.server.services.impl.LogServiceImpl;
|
||||
import mage.server.tournament.TournamentController;
|
||||
|
|
@ -105,7 +106,7 @@ public class TableController {
|
|||
} else {
|
||||
controllerName = "System";
|
||||
}
|
||||
table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), match);
|
||||
table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), match);
|
||||
chatId = ChatManager.getInstance().createChatSession("Match Table " + table.getId());
|
||||
init();
|
||||
}
|
||||
|
|
@ -124,7 +125,7 @@ public class TableController {
|
|||
} else {
|
||||
controllerName = "System";
|
||||
}
|
||||
table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), tournament);
|
||||
table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), TableRecorderImpl.getInstance(), tournament);
|
||||
chatId = ChatManager.getInstance().createChatSession("Tourn. table " + table.getId());
|
||||
}
|
||||
|
||||
|
|
@ -237,6 +238,7 @@ public class TableController {
|
|||
|
||||
TournamentPlayer newTournamentPlayer = tournament.getPlayer(newPlayer.getId());
|
||||
newTournamentPlayer.setState(oldTournamentPlayer.getState());
|
||||
newTournamentPlayer.setReplacedTournamentPlayer(oldTournamentPlayer);
|
||||
|
||||
DraftManager.getInstance().getController(table.getId()).replacePlayer(oldPlayer, newPlayer);
|
||||
return true;
|
||||
|
|
@ -957,26 +959,16 @@ public class TableController {
|
|||
return getTable().getState();
|
||||
}
|
||||
|
||||
public synchronized boolean changeTableState(TableState newTableState) {
|
||||
switch (newTableState) {
|
||||
case WAITING:
|
||||
if (getTable().getState().equals(TableState.STARTING)) {
|
||||
// tournament already started
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case STARTING:
|
||||
if (!getTable().getState().equals(TableState.READY_TO_START)) {
|
||||
// tournament is not ready, can't start
|
||||
return false;
|
||||
}
|
||||
if (!table.allSeatsAreOccupied()) {
|
||||
logger.debug("Not alle Seats are occupied: stop start tableId:" + table.getId());
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
public synchronized boolean changeTableStateToStarting() {
|
||||
if (!getTable().getState().equals(TableState.READY_TO_START)) {
|
||||
// tournament is not ready, can't start
|
||||
return false;
|
||||
}
|
||||
getTable().setState(newTableState);
|
||||
if (!table.allSeatsAreOccupied()) {
|
||||
logger.debug("Not alle Seats are occupied: stop start tableId:" + table.getId());
|
||||
return false;
|
||||
}
|
||||
getTable().setState(TableState.STARTING);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,11 +43,14 @@ import mage.constants.TableState;
|
|||
import mage.game.GameException;
|
||||
import mage.game.Table;
|
||||
import mage.game.match.MatchOptions;
|
||||
import mage.game.result.ResultProtos.UserStatsProto;
|
||||
import mage.game.tournament.TournamentOptions;
|
||||
import mage.server.RoomImpl;
|
||||
import mage.server.TableManager;
|
||||
import mage.server.User;
|
||||
import mage.server.UserManager;
|
||||
import mage.server.record.UserStats;
|
||||
import mage.server.record.UserStatsRepository;
|
||||
import mage.server.tournament.TournamentManager;
|
||||
import mage.server.util.ConfigSettings;
|
||||
import mage.server.util.ThreadExecutor;
|
||||
|
|
@ -91,6 +94,74 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
return tableView;
|
||||
}
|
||||
|
||||
private static void joinStrings(StringBuilder joined, List<String> strings, String separator) {
|
||||
for (int i = 0; i < strings.size(); ++i) {
|
||||
if (i > 0) {
|
||||
joined.append(separator);
|
||||
}
|
||||
joined.append(strings.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
private static String joinBuilders(List<StringBuilder> builders) {
|
||||
if (builders.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder builder = builders.get(0);
|
||||
for (int i = 1; i < builders.size(); ++i) {
|
||||
builder.append(" ");
|
||||
builder.append(builders.get(i));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static String userStatsToString(UserStatsProto proto) {
|
||||
List<StringBuilder> builders = new ArrayList();
|
||||
if (proto.getMatches() > 0) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Matches:");
|
||||
builder.append(proto.getMatches());
|
||||
List<String> quit = new ArrayList();
|
||||
if (proto.getMatchesIdleTimeout() > 0) {
|
||||
quit.add("I:" + Integer.toString(proto.getMatchesIdleTimeout()));
|
||||
}
|
||||
if (proto.getMatchesTimerTimeout() > 0) {
|
||||
quit.add("T:" + Integer.toString(proto.getMatchesTimerTimeout()));
|
||||
}
|
||||
if (proto.getMatchesQuit() > 0) {
|
||||
quit.add("Q:" + Integer.toString(proto.getMatchesQuit()));
|
||||
}
|
||||
if (quit.size() > 0) {
|
||||
builder.append(" (");
|
||||
joinStrings(builder, quit, " ");
|
||||
builder.append(")");
|
||||
}
|
||||
builders.add(builder);
|
||||
}
|
||||
if (proto.getTourneys() > 0) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Tourneys:");
|
||||
builder.append(proto.getTourneys());
|
||||
List<String> quit = new ArrayList();
|
||||
if (proto.getTourneysQuitDuringDrafting() > 0) {
|
||||
quit.add("D:" + Integer.toString(proto.getTourneysQuitDuringDrafting()));
|
||||
}
|
||||
if (proto.getTourneysQuitDuringConstruction() > 0) {
|
||||
quit.add("C:" + Integer.toString(proto.getTourneysQuitDuringConstruction()));
|
||||
}
|
||||
if (proto.getTourneysQuitDuringRound() > 0) {
|
||||
quit.add("R:" + Integer.toString(proto.getTourneysQuitDuringRound()));
|
||||
}
|
||||
if (quit.size() > 0) {
|
||||
builder.append(" (");
|
||||
joinStrings(builder, quit, " ");
|
||||
builder.append(")");
|
||||
}
|
||||
builders.add(builder);
|
||||
}
|
||||
return joinBuilders(builders);
|
||||
}
|
||||
|
||||
private void update() {
|
||||
ArrayList<TableView> tableList = new ArrayList<>();
|
||||
ArrayList<MatchView> matchList = new ArrayList<>();
|
||||
|
|
@ -100,11 +171,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
if (table.getState() != TableState.FINISHED) {
|
||||
tableList.add(new TableView(table));
|
||||
} else if (matchList.size() < 50) {
|
||||
if (table.isTournament()) {
|
||||
matchList.add(new MatchView(table));
|
||||
} else {
|
||||
matchList.add(new MatchView(table));
|
||||
}
|
||||
matchList.add(new MatchView(table));
|
||||
} else {
|
||||
// more since 50 matches finished since this match so remove it
|
||||
if (table.isTournament()) {
|
||||
|
|
@ -117,13 +184,19 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
matchView = matchList;
|
||||
List<UsersView> users = new ArrayList<>();
|
||||
for (User user : UserManager.getInstance().getUsers()) {
|
||||
String history = null;
|
||||
UserStats stats = UserStatsRepository.instance.getUser(user.getName());
|
||||
if (stats != null) {
|
||||
history = userStatsToString(stats.getProto());
|
||||
}
|
||||
try {
|
||||
users.add(new UsersView(user.getUserData().getFlagName(), user.getName(), user.getInfo(), user.getGameInfo(), user.getPingInfo()));
|
||||
users.add(new UsersView(user.getUserData().getFlagName(), user.getName(), history, user.getInfo(), user.getGameInfo(), user.getPingInfo()));
|
||||
} catch (Exception ex) {
|
||||
logger.fatal("User update exception: " + user.getName() + " - " + ex.toString(), ex);
|
||||
users.add(new UsersView(
|
||||
(user.getUserData() != null && user.getUserData().getFlagName() != null) ? user.getUserData().getFlagName() : "world",
|
||||
user.getName() != null ? user.getName() : "<no name>",
|
||||
history != null ? history : "<no history>",
|
||||
user.getInfo() != null ? user.getInfo() : "<no info>",
|
||||
"[exception]",
|
||||
user.getPingInfo() != null ? user.getPingInfo() : "<no ping>"));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package mage.server.record;
|
||||
|
||||
import com.j256.ormlite.field.DataType;
|
||||
import com.j256.ormlite.field.DatabaseField;
|
||||
import com.j256.ormlite.table.DatabaseTable;
|
||||
import mage.game.result.ResultProtos.TableProto;
|
||||
import org.mage.mage.shaded.protobuf.InvalidProtocolBufferException;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
@DatabaseTable(tableName = "table_history")
|
||||
public class TableRecord {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TableRecord.class);
|
||||
|
||||
@DatabaseField(dataType = DataType.BYTE_ARRAY, indexName = "proto_index", unique = true)
|
||||
protected byte[] proto;
|
||||
|
||||
@DatabaseField(indexName = "end_time_ms")
|
||||
protected long endTimeMs;
|
||||
|
||||
public TableRecord() {
|
||||
}
|
||||
|
||||
public TableRecord(TableProto proto, long endTimeMs) {
|
||||
this.proto = proto.toByteArray();
|
||||
this.endTimeMs = endTimeMs;
|
||||
}
|
||||
|
||||
public TableProto getProto() {
|
||||
try {
|
||||
return TableProto.parseFrom(this.proto);
|
||||
} catch (InvalidProtocolBufferException ex) {
|
||||
logger.error("Failed to parse serialized proto", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package mage.server.record;
|
||||
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
import com.j256.ormlite.dao.DaoManager;
|
||||
import com.j256.ormlite.jdbc.JdbcConnectionSource;
|
||||
import com.j256.ormlite.stmt.QueryBuilder;
|
||||
import com.j256.ormlite.support.ConnectionSource;
|
||||
import com.j256.ormlite.support.DatabaseConnection;
|
||||
import com.j256.ormlite.table.TableUtils;
|
||||
import java.io.File;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import mage.cards.repository.RepositoryUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public enum TableRecordRepository {
|
||||
|
||||
instance;
|
||||
|
||||
private static final String JDBC_URL = "jdbc:sqlite:./db/table_record.db";
|
||||
private static final String VERSION_ENTITY_NAME = "table_record";
|
||||
// raise this if db structure was changed
|
||||
private static final long DB_VERSION = 0;
|
||||
|
||||
private Dao<TableRecord, Object> dao;
|
||||
|
||||
private TableRecordRepository() {
|
||||
File file = new File("db");
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
try {
|
||||
ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL);
|
||||
boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, DB_VERSION);
|
||||
|
||||
if (obsolete) {
|
||||
TableUtils.dropTable(connectionSource, TableRecord.class, true);
|
||||
}
|
||||
|
||||
TableUtils.createTableIfNotExists(connectionSource, TableRecord.class);
|
||||
dao = DaoManager.createDao(connectionSource, TableRecord.class);
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(TableRecordRepository.class).error("Error creating table_record repository - ", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(TableRecord tableHistory) {
|
||||
try {
|
||||
dao.create(tableHistory);
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(TableRecordRepository.class).error("Error adding a table_record to DB - ", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public List<TableRecord> getAfter(long endTimeMs) {
|
||||
try {
|
||||
QueryBuilder<TableRecord, Object> qb = dao.queryBuilder();
|
||||
qb.where().gt("endTimeMs", endTimeMs);
|
||||
qb.orderBy("endTimeMs", true);
|
||||
return dao.query(qb.prepare());
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(TableRecordRepository.class).error("Error getting table_records from DB - ", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void closeDB() {
|
||||
try {
|
||||
if (dao != null && dao.getConnectionSource() != null) {
|
||||
DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection();
|
||||
conn.executeStatement("shutdown compact", 0);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(TableRecordRepository.class).error("Error closing table_record repository - ", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package mage.server.record;
|
||||
|
||||
import mage.game.Table;
|
||||
import mage.game.Table.TableRecorder;
|
||||
import mage.game.result.ResultProtos.TableProto;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public class TableRecorderImpl implements TableRecorder {
|
||||
|
||||
private static TableRecorderImpl INSTANCE = new TableRecorderImpl();
|
||||
private static final Logger logger = Logger.getLogger(TableRecorderImpl.class);
|
||||
|
||||
public static TableRecorderImpl getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public void record(Table table) {
|
||||
TableProto proto = table.toProto();
|
||||
logger.info("Adding record:\n" + proto.toString());
|
||||
TableRecordRepository.instance.add(new TableRecord(proto, proto.getEndTimeMs()));
|
||||
}
|
||||
}
|
||||
45
Mage.Server/src/main/java/mage/server/record/UserStats.java
Normal file
45
Mage.Server/src/main/java/mage/server/record/UserStats.java
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package mage.server.record;
|
||||
|
||||
import com.j256.ormlite.field.DataType;
|
||||
import com.j256.ormlite.field.DatabaseField;
|
||||
import com.j256.ormlite.table.DatabaseTable;
|
||||
import mage.game.result.ResultProtos.UserStatsProto;
|
||||
import org.mage.mage.shaded.protobuf.InvalidProtocolBufferException;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
@DatabaseTable(tableName = "user_stats")
|
||||
public class UserStats {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TableRecord.class);
|
||||
|
||||
@DatabaseField(indexName = "user_name_index", unique = true, id = true)
|
||||
protected String userName;
|
||||
|
||||
@DatabaseField(dataType = DataType.BYTE_ARRAY)
|
||||
protected byte[] proto;
|
||||
|
||||
@DatabaseField(indexName = "end_time_ms_index")
|
||||
protected long endTimeMs;
|
||||
|
||||
public UserStats() {
|
||||
}
|
||||
|
||||
public UserStats(UserStatsProto proto, long endTimeMs) {
|
||||
this.userName = proto.getName();
|
||||
this.proto = proto.toByteArray();
|
||||
this.endTimeMs = endTimeMs;
|
||||
}
|
||||
|
||||
public UserStatsProto getProto() {
|
||||
try {
|
||||
return UserStatsProto.parseFrom(this.proto);
|
||||
} catch (InvalidProtocolBufferException ex) {
|
||||
logger.error("Failed to parse serialized proto", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getEndTimeMs() {
|
||||
return this.endTimeMs;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package mage.server.record;
|
||||
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
import com.j256.ormlite.dao.DaoManager;
|
||||
import com.j256.ormlite.jdbc.JdbcConnectionSource;
|
||||
import com.j256.ormlite.stmt.QueryBuilder;
|
||||
import com.j256.ormlite.support.ConnectionSource;
|
||||
import com.j256.ormlite.support.DatabaseConnection;
|
||||
import com.j256.ormlite.table.TableUtils;
|
||||
import java.io.File;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import mage.cards.repository.RepositoryUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public enum UserStatsRepository {
|
||||
|
||||
instance;
|
||||
|
||||
private static final String JDBC_URL = "jdbc:sqlite:./db/user_stats.db";
|
||||
private static final String VERSION_ENTITY_NAME = "user_stats";
|
||||
// raise this if db structure was changed
|
||||
private static final long DB_VERSION = 0;
|
||||
|
||||
private Dao<UserStats, Object> dao;
|
||||
|
||||
private UserStatsRepository() {
|
||||
File file = new File("db");
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
try {
|
||||
ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL);
|
||||
boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, DB_VERSION);
|
||||
|
||||
if (obsolete) {
|
||||
TableUtils.dropTable(connectionSource, UserStats.class, true);
|
||||
}
|
||||
|
||||
TableUtils.createTableIfNotExists(connectionSource, UserStats.class);
|
||||
dao = DaoManager.createDao(connectionSource, UserStats.class);
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(UserStatsRepository.class).error("Error creating user_stats repository - ", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(UserStats userStats) {
|
||||
try {
|
||||
dao.create(userStats);
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(UserStatsRepository.class).error("Error adding a user_stats to DB - ", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void update(UserStats userStats) {
|
||||
try {
|
||||
dao.update(userStats);
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(UserStatsRepository.class).error("Error updating a user_stats in DB - ", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public UserStats getUser(String userName) {
|
||||
try {
|
||||
QueryBuilder<UserStats, Object> qb = dao.queryBuilder();
|
||||
qb.where().eq("userName", userName);
|
||||
List<UserStats> users = dao.query(qb.prepare());
|
||||
if (users.size() == 1) {
|
||||
return users.get(0);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(UserStatsRepository.class).error("Error getting a user from DB - ", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<UserStats> getAllUsers() {
|
||||
try {
|
||||
QueryBuilder<UserStats, Object> qb = dao.queryBuilder();
|
||||
return dao.query(qb.prepare());
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(UserStatsRepository.class).error("Error getting all users from DB - ", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getLatestEndTimeMs() {
|
||||
try {
|
||||
QueryBuilder<UserStats, Object> qb = dao.queryBuilder();
|
||||
qb.orderBy("endTimeMs", false).limit(1);
|
||||
List<UserStats> users = dao.query(qb.prepare());
|
||||
if (users.size() == 1) {
|
||||
return users.get(0).getEndTimeMs();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(UserStatsRepository.class).error("Error getting the latest end time from DB - ", ex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void closeDB() {
|
||||
try {
|
||||
if (dao != null && dao.getConnectionSource() != null) {
|
||||
DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection();
|
||||
conn.executeStatement("shutdown compact", 0);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(UserStatsRepository.class).error("Error closing user_stats repository - ", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ import mage.game.events.TableEvent;
|
|||
import static mage.game.events.TableEvent.EventType.CONSTRUCT;
|
||||
import mage.game.match.Match;
|
||||
import mage.game.match.MatchOptions;
|
||||
import mage.game.result.ResultProtos.TourneyQuitStatus;
|
||||
import mage.game.tournament.Tournament;
|
||||
import mage.game.tournament.TournamentPairing;
|
||||
import mage.game.tournament.TournamentPlayer;
|
||||
|
|
@ -351,31 +352,34 @@ public class TournamentController {
|
|||
tournamentSession.setKilled();
|
||||
if (tournamentPlayer.isInTournament()) {
|
||||
String info;
|
||||
TourneyQuitStatus status;
|
||||
if (tournament.isDoneConstructing()) {
|
||||
info = new StringBuilder("during round ").append(tournament.getRounds().size()).toString();
|
||||
// quit active matches of that tournament
|
||||
TableManager.getInstance().userQuitTournamentSubTables(tournament.getId(), userId);
|
||||
} else {
|
||||
if (tournamentPlayer.getState().equals(TournamentPlayerState.DRAFTING)) {
|
||||
info = "during Draft phase";
|
||||
if (!checkToReplaceDraftPlayerByAi(userId, tournamentPlayer)) {
|
||||
this.abortDraftTournament();
|
||||
} else {
|
||||
DraftController draftController = DraftManager.getInstance().getController(tableId);
|
||||
if (draftController != null) {
|
||||
DraftSession draftSession = draftController.getDraftSession(playerId);
|
||||
if (draftSession != null) {
|
||||
DraftManager.getInstance().kill(draftSession.getDraftId(), userId);
|
||||
}
|
||||
status = TourneyQuitStatus.DURING_ROUND;
|
||||
} else if (tournamentPlayer.getState().equals(TournamentPlayerState.DRAFTING)) {
|
||||
info = "during Draft phase";
|
||||
if (!checkToReplaceDraftPlayerByAi(userId, tournamentPlayer)) {
|
||||
this.abortDraftTournament();
|
||||
} else {
|
||||
DraftController draftController = DraftManager.getInstance().getController(tableId);
|
||||
if (draftController != null) {
|
||||
DraftSession draftSession = draftController.getDraftSession(playerId);
|
||||
if (draftSession != null) {
|
||||
DraftManager.getInstance().kill(draftSession.getDraftId(), userId);
|
||||
}
|
||||
}
|
||||
} else if (tournamentPlayer.getState().equals(TournamentPlayerState.CONSTRUCTING)) {
|
||||
info = "during Construction phase";
|
||||
} else {
|
||||
info = "";
|
||||
}
|
||||
status = TourneyQuitStatus.DURING_DRAFTING;
|
||||
} else if (tournamentPlayer.getState().equals(TournamentPlayerState.CONSTRUCTING)) {
|
||||
info = "during Construction phase";
|
||||
status = TourneyQuitStatus.DURING_CONSTRUCTION;
|
||||
} else {
|
||||
info = "";
|
||||
status = TourneyQuitStatus.NO_TOURNEY_QUIT;
|
||||
}
|
||||
tournamentPlayer.setQuit(info);
|
||||
tournamentPlayer.setQuit(info, status);
|
||||
tournament.quit(playerId);
|
||||
tournamentSession.quit();
|
||||
ChatManager.getInstance().broadcast(chatId, "", tournamentPlayer.getPlayer().getLogName() + " has quit the tournament", MessageColor.BLACK, true, MessageType.STATUS, SoundToPlay.PlayerQuitTournament);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue