package onlinefrontlines.game;
import java.text.DateFormat;
import java.util.*;
import java.sql.SQLException;
import onlinefrontlines.auth.UserCache;
import onlinefrontlines.game.actions.*;
import onlinefrontlines.utils.CacheException;
import onlinefrontlines.utils.DbQueryHelper;
import onlinefrontlines.utils.DbStoredProcHelper;
import onlinefrontlines.utils.Tools;
/**
* This class communicates with the database and manages reading/writing GameState objects
*
* @see onlinefrontlines.game.GameState
* @author jorrit
*
* Copyright (C) 2009-2013 Jorrit Rouwe
*
* This file is part of Online Frontlines.
*
* Online Frontlines is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Online Frontlines is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Online Frontlines. If not, see <http://www.gnu.org/licenses/>.
*/
public class GameStateDAO
{
/**
* Summary of a game for listing purposes
*/
public static class Summary
{
/**
* Game id
*/
public int id;
/**
* Country config name
*/
public String countryConfigName;
/**
* Map id
*/
public int mapId;
/**
* Current turn
*/
public int turnNumber;
/**
* Turn end time
*/
public long turnEndTime;
/**
* Current player mask (bit 0 = Faction 1, bit 1 = Faction 2)
*/
public int currentPlayerMask;
/**
* Winning faction
*/
public Faction winningFaction = Faction.invalid;
/**
* Players
*/
public int player1Id;
public int player2Id;
public String player1Name;
public String player2Name;
/**
* Game id
*/
public int getId()
{
return id;
}
/**
* Country config name
*/
public String getCountryConfigName()
{
return countryConfigName;
}
/**
* Map id
*/
public int getMapId()
{
return mapId;
}
/**
* Current turn
*/
public int getTurnNumber()
{
return turnNumber;
}
/**
* Check if player 1 can perform an action
*/
public boolean getPlayer1CanPerformAction()
{
return (currentPlayerMask & 1) != 0;
}
/**
* Check if player 2 can perform an action
*/
public boolean getPlayer2CanPerformAction()
{
return (currentPlayerMask & 2) != 0;
}
/**
* User id of player 1
*/
public int getPlayer1Id()
{
return player1Id;
}
/**
* Username of player 1
*/
public String getPlayer1Name()
{
return player1Name;
}
/**
* User id of player 2
*/
public int getPlayer2Id()
{
return player2Id;
}
/**
* Username of player 2
*/
public String getPlayer2Name()
{
return player2Name;
}
/**
* Check if game has ended
*/
public boolean getHasGameEnded()
{
return winningFaction != Faction.invalid;
}
/**
* Check if it is a users turn to move
*
* @param userId User to check for
*/
public boolean getIsMyTurn(int userId)
{
return (player1Id == userId && getPlayer1CanPerformAction()) || (player2Id == userId && getPlayer2CanPerformAction());
}
}
/**
* Comparator for sorting summaries
*/
private static class SummarySorter implements Comparator<Summary>
{
public SummarySorter(int currentUserId)
{
this.currentUserId = currentUserId;
}
public int compare(Summary s1, Summary s2)
{
// First sort on finished or not (finished games go last)
boolean s1Finished = s1.winningFaction != Faction.invalid;
boolean s2Finished = s2.winningFaction != Faction.invalid;
if (s1Finished != s2Finished)
return s2Finished? -1 : 1;
// Then sort on if the current user can do something (games where it is my turn go first)
boolean s1MyTurn = s1.getIsMyTurn(currentUserId);
boolean s2MyTurn = s2.getIsMyTurn(currentUserId);
if (s1MyTurn != s2MyTurn)
return s1MyTurn? -1 : 1;
// Finally sort on turn end time (closer to now goes first)
return s1.turnEndTime - s2.turnEndTime < 0? -1 : 1;
}
private int currentUserId;
}
/**
* Get list number games that the user can continue playing
*
* @param userId User id of the user that wants to continue playing
* @return Number of games
*/
public static int getNumberOfGamesToContinue(int userId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
helper.prepareQuery("SELECT COUNT(1) FROM games WHERE (userId1=? OR userId2=?) AND (winningFaction=? OR winningTime>?) AND (corrupt=0)");
helper.setInt(1, userId);
helper.setInt(2, userId);
helper.setInt(3, Faction.toInt(Faction.invalid));
helper.setLong(4, Calendar.getInstance().getTime().getTime() - 2L * 24L * 60L * 60L * 1000L);
helper.executeQuery();
if (helper.nextRecord())
return helper.getInt(1);
else
return 0;
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Get list of games that the user needs to make a move
*/
public static List<Integer> getGamesIdsToContinue(int userId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
helper.prepareQuery("SELECT id FROM games WHERE ((userId1=? AND (currentPlayer & 1)<>0) OR (userId2=? AND (currentPlayer & 2)<>0)) AND (winningFaction=?) AND (corrupt=0)");
helper.setInt(1, userId);
helper.setInt(2, userId);
helper.setInt(3, Faction.toInt(Faction.invalid));
helper.executeQuery();
ArrayList<Integer> rv = new ArrayList<Integer>();
while (helper.nextRecord())
rv.add(helper.getInt(1));
return rv;
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Get list of games that the user can continue playing
*
* @param userId User id of the user that wants to continue playing
* @return List of games that the user can continue
*/
public static Summary[] getGamesToContinue(int userId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
ArrayList<Summary> rv = new ArrayList<Summary>();
helper.prepareQuery("SELECT games.id, country_configs.name, user1.id, user2.id, user1.username, user2.username, country_configs.mapId, turnNumber, currentPlayer, winningFaction, turnEndTime FROM games"
+ " INNER JOIN country_configs ON country_configs.id=countryConfigId"
+ " LEFT JOIN users AS user1 ON user1.id=userId1"
+ " LEFT JOIN users AS user2 ON user2.id=userId2"
+ " WHERE (userId1=? OR userId2=?) AND (winningFaction=? OR winningTime>?) AND (corrupt=0)");
helper.setInt(1, userId);
helper.setInt(2, userId);
helper.setInt(3, Faction.toInt(Faction.invalid));
helper.setLong(4, Calendar.getInstance().getTime().getTime() - 2L * 24L * 60L * 60L * 1000L);
helper.executeQuery();
while (helper.nextRecord())
{
Summary s = new Summary();
s.id = helper.getInt(1);
s.countryConfigName = helper.getString(2);
s.player1Id = helper.getInt(3);
s.player2Id = helper.getInt(4);
s.player1Name = helper.getString(5);
s.player2Name = helper.getString(6);
s.mapId = helper.getInt(7);
s.turnNumber = helper.getInt(8);
s.currentPlayerMask = helper.getInt(9);
s.winningFaction = Faction.fromInt(helper.getInt(10));
s.turnEndTime = helper.getLong(11);
rv.add(s);
}
// Sort the results
Summary[] sortedList = rv.toArray(new Summary[0]);
Arrays.sort(sortedList, new SummarySorter(userId));
return sortedList;
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Get list of games that have timed out
*
* @return List of games that have timed out
*/
public static ArrayList<Integer> getTimedOutGames() throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
ArrayList<Integer> rv = new ArrayList<Integer>();
helper.prepareQuery("SELECT id FROM games"
+ " WHERE (turnEndTime IS NOT NULL) AND (?>turnEndTime) AND (winningFaction=?) AND (corrupt=0)");
helper.setLong(1, Calendar.getInstance().getTime().getTime());
helper.setInt(2, Faction.toInt(Faction.invalid));
helper.executeQuery();
while (helper.nextRecord())
rv.add(helper.getInt(1));
return rv;
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Get list of games that the user can join playing
*
* @param userId User id of the user that wants to join a game
* @return List of games that are joinable
*/
public static ArrayList<Summary> getJoinableGames(int userId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
ArrayList<Summary> rv = new ArrayList<Summary>();
helper.prepareQuery("SELECT games.id, country_configs.name, user1.id, user1.username FROM games"
+ " INNER JOIN country_configs ON country_configs.id=countryConfigId"
+ " LEFT JOIN users AS user1 ON user1.id=userId1"
+ " WHERE (userId1<>?)"
+ " AND (userId2 IS NULL)"
+ " AND (winningFaction=?)"
+ " AND (corrupt=0)");
helper.setInt(1, userId);
helper.setInt(2, Faction.toInt(Faction.invalid));
helper.executeQuery();
while (helper.nextRecord())
{
Summary s = new Summary();
s.id = helper.getInt(1);
s.countryConfigName = helper.getString(2);
s.player1Id = helper.getInt(3);
s.player1Name = helper.getString(4);
rv.add(s);
}
return rv;
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Get summary of game
*
* @param gameId Game id of game
* @return Summary
* @throws SQLException
*/
public static Summary getGameSummary(int gameId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
helper.prepareQuery("SELECT country_configs.name, user1.id, user2.id, user1.username, user2.username, winningFaction FROM games"
+ " INNER JOIN country_configs ON country_configs.id=countryConfigId"
+ " LEFT JOIN users AS user1 ON user1.id=userId1"
+ " LEFT JOIN users AS user2 ON user2.id=userId2"
+ " WHERE games.id=?");
helper.setInt(1, gameId);
helper.executeQuery();
if (!helper.nextRecord())
return null;
Summary s = new Summary();
s.id = gameId;
s.countryConfigName = helper.getString(1);
s.player1Id = helper.getInt(2);
s.player2Id = helper.getInt(3);
s.player1Name = helper.getString(4);
s.player2Name = helper.getString(5);
s.winningFaction = Faction.fromInt(helper.getInt(6));
return s;
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Game in progress for a lobby
*/
public static class GameForLobby
{
public int gameId;
public int attackerUserId;
public int defenderUserId;
public int attackedCountryX;
public int attackedCountryY;
public int defendedCountryX;
public int defendedCountryY;
public Faction winningFaction;
}
/**
* Query to get games for a lobby
*/
private static final String gamesForLobbiesQuery = "SELECT id, userId1, userId2, attackedCountryX, attackedCountryY, defendedCountryX, defendedCountryY, winningFaction FROM games";
/**
* Helper function to fill in an array of games for a lobby
*/
private static ArrayList<GameForLobby> fillGamesForLobbies(DbQueryHelper helper) throws SQLException
{
ArrayList<GameForLobby> games = new ArrayList<GameForLobby>();
while (helper.nextRecord())
{
GameForLobby g = new GameForLobby();
g.gameId = helper.getInt(1);
g.attackerUserId = helper.getInt(2);
g.defenderUserId = helper.getInt(3);
g.attackedCountryX = helper.getInt(4);
g.attackedCountryY = helper.getInt(5);
g.defendedCountryX = helper.getInt(6);
g.defendedCountryY = helper.getInt(7);
g.winningFaction = Faction.fromInt(helper.getInt(8));
games.add(g);
}
return games;
}
/**
* Get games in progress for a specific lobby
*
* @param lobbyId Lobby id of lobby to query for
*/
public static ArrayList<GameForLobby> getGamesForLobby(int lobbyId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
helper.prepareQuery(gamesForLobbiesQuery + " WHERE lobbyId=? AND lobbyProcessedGame=0");
helper.setInt(1, lobbyId);
helper.executeQuery();
return fillGamesForLobbies(helper);
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Get list of games that need to be processed by a lobby
*
* @param lobbyId Lobby to get games for
* @return List of games that should be processed
* @throws SQLException
*/
public static ArrayList<GameForLobby> getGamesForLobbyToProcess(int lobbyId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
helper.prepareQuery(gamesForLobbiesQuery + " WHERE (lobbyId=? AND lobbyProcessedGame=0 AND (winningFaction<>? OR corrupt=1))");
helper.setInt(1, lobbyId);
helper.setInt(2, Faction.toInt(Faction.invalid));
helper.executeQuery();
return fillGamesForLobbies(helper);
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Mark game processed by lobby
*
* @param gameId Id of game
*/
public static void markGameProcessedByLobby(int gameId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
// Create record
helper.prepareQuery("UPDATE games SET lobbyProcessedGame=1 WHERE id=?");
helper.setInt(1, gameId);
helper.executeUpdate();
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Get number of games in progress for a specific lobby
*
* @param lobbyId Lobby id of lobby to query for
*/
public static int getGameCountForLobby(int lobbyId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
helper.prepareQuery("SELECT COUNT(1) FROM games WHERE lobbyId=? AND winningFaction=? AND corrupt=0");
helper.setInt(1, lobbyId);
helper.setInt(2, Faction.toInt(Faction.invalid));
helper.executeQuery();
helper.nextRecord();
return helper.getInt(1);
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Class that contains results of multiple games
*/
public static class GameResults
{
/**
* Number of games still in progress
*/
public int inProgress;
/**
* Number of games that faction 1 won
*/
public int f1Wins;
/**
* Number of games that faction 2 won
*/
public int f2Wins;
/**
* Number of games that resulted in a draw
*/
public int draws;
/**
* Number of games still in progress
*/
public int getInProgress()
{
return inProgress;
}
/**
* Number of games that faction 1 won
*/
public int getF1Wins()
{
return f1Wins;
}
/**
* Number of games that faction 2 won
*/
public int getF2Wins()
{
return f2Wins;
}
/**
* Number of games that resulted in a draw
*/
public int getDraws()
{
return draws;
}
/**
* Get total amount of games played
*/
public int getTotal()
{
return inProgress + f1Wins + f2Wins + draws;
}
}
/**
* Class that contains results of multiple games ordered by map
*/
public static class GameResultsByMap extends GameResults
{
/**
* Id of the map that this results belong to
*/
public int mapId;
/**
* Id of the map that this results belong to
*/
public int getMapId()
{
return mapId;
}
/**
* Get map name
*/
public String getMapName() throws CacheException
{
return MapConfigCache.getInstance().get(mapId).name;
}
}
/**
* Class that contains results of multiple games ordered by country
*/
public static class GameResultsByCountry extends GameResults
{
/**
* Id of the country that this results belong to
*/
public int countryConfigId;
/**
* Id of the country that this results belong to
*/
public int getCountryConfigId()
{
return countryConfigId;
}
/**
* Get country config name
*/
public String getCountryConfigName() throws CacheException
{
return CountryConfigCache.getInstance().get(countryConfigId).name;
}
}
/**
* Get game results by country
*/
public static ArrayList<GameResultsByCountry> getGameResultsByCountryConfig() throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
ArrayList<GameResultsByCountry> rv = new ArrayList<GameResultsByCountry>();
helper.prepareQuery("SELECT countryConfigId, SUM(IF(winningFaction = 0, 1, 0)) AS inProgress, SUM(IF(winningFaction = 1, 1, 0)) AS f1, SUM(IF(winningFaction = 2, 1, 0)) AS f2, SUM(IF(winningFaction = 3, 1, 0)) AS draw FROM games WHERE userId2 IS NOT NULL GROUP BY countryConfigId");
helper.executeQuery();
while (helper.nextRecord())
{
GameResultsByCountry s = new GameResultsByCountry();
s.countryConfigId = helper.getInt(1);
s.inProgress = helper.getInt(2);
s.f1Wins = helper.getInt(3);
s.f2Wins = helper.getInt(4);
s.draws = helper.getInt(5);
rv.add(s);
}
return rv;
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Get game results by country
*/
public static ArrayList<GameResultsByMap> getGameResultsByMap() throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
ArrayList<GameResultsByMap> rv = new ArrayList<GameResultsByMap>();
helper.prepareQuery("SELECT country_configs.mapId, SUM(IF(winningFaction = 0, 1, 0)) AS inProgress, SUM(IF(winningFaction = 1, 1, 0)) AS f1, SUM(IF(winningFaction = 2, 1, 0)) AS f2, SUM(IF(winningFaction = 3, 1, 0)) AS draw FROM games LEFT JOIN country_configs ON country_configs.id = games.countryConfigId WHERE userId2 IS NOT NULL GROUP BY mapId");
helper.executeQuery();
while (helper.nextRecord())
{
GameResultsByMap s = new GameResultsByMap();
s.mapId = helper.getInt(1);
s.inProgress = helper.getInt(2);
s.f1Wins = helper.getInt(3);
s.f2Wins = helper.getInt(4);
s.draws = helper.getInt(5);
rv.add(s);
}
return rv;
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Summary of a game for listing purposes
*/
public static class FinishedGame
{
/**
* Game id
*/
public int id;
/**
* Opponent
*/
public int opponentId;
public String opponentName;
/**
* Game time
*/
public long winningTime;
/**
* Game result
*/
public String result;
/**
* Get game id
*/
public int getId()
{
return id;
}
/**
* Opponent user id
*/
public int getOpponentId()
{
return opponentId;
}
/**
* Get opponent name
*/
public String getOpponentName()
{
return opponentName;
}
/**
* Get winning time as a string
*/
public String getWinningDateString()
{
return DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.US).format(new Date(winningTime));
}
/**
* Get result
*/
public String getResult()
{
return result;
}
}
/**
* Get list of games that the user finished recently
*
* @param userId User id of the user
* @return List of finished games
*/
public static ArrayList<FinishedGame> getFinishedGames(int userId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
ArrayList<FinishedGame> rv = new ArrayList<FinishedGame>();
helper.prepareQuery("SELECT games.id, user1.id, user2.id, user1.username, user2.username, games.winningTime, games.winningFaction FROM games"
+ " LEFT JOIN users AS user1 ON user1.id=userId1"
+ " LEFT JOIN users AS user2 ON user2.id=userId2"
+ " WHERE (userId1=? OR userId2=?) AND (userId2 IS NOT NULL) AND (winningFaction<>?) AND (corrupt=0)"
+ " ORDER BY games.winningTime DESC LIMIT 10");
helper.setInt(1, userId);
helper.setInt(2, userId);
helper.setInt(3, Faction.toInt(Faction.invalid));
helper.executeQuery();
while (helper.nextRecord())
{
FinishedGame s = new FinishedGame();
s.id = helper.getInt(1);
boolean playerIsFaction1 = helper.getInt(2) == userId;
if (playerIsFaction1)
{
s.opponentId = helper.getInt(3);
s.opponentName = helper.getString(5);
}
else
{
s.opponentId = helper.getInt(2);
s.opponentName = helper.getString(4);
}
s.winningTime = helper.getLong(6);
switch (Faction.fromInt(helper.getInt(7)))
{
case f1:
s.result = playerIsFaction1? "won" : "lost";
break;
case f2:
s.result = playerIsFaction1? "lost" : "won";
break;
default:
s.result = "draw";
break;
}
rv.add(s);
}
return rv;
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Create an entry for a game in the database
*
* @param gameState Game to create an entry for
* @throws SQLException
*/
public static void create(GameState gameState) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
// Create record
helper.prepareQuery("INSERT INTO games (countryConfigId, faction1IsRed, faction1Starts, lobbyId, attackedCountryX, attackedCountryY, defendedCountryX, defendedCountryY, creationTime, winningFaction, playByMail, actions) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
helper.setInt(1, gameState.countryConfig.id);
helper.setInt(2, gameState.faction1IsRed? 1 : 0);
helper.setInt(3, gameState.faction1Starts? 1 : 0);
helper.setInt(4, gameState.lobbyId);
helper.setInt(5, gameState.attackedCountryX);
helper.setInt(6, gameState.attackedCountryY);
helper.setInt(7, gameState.defendedCountryX);
helper.setInt(8, gameState.defendedCountryY);
helper.setLong(9, Calendar.getInstance().getTime().getTime());
helper.setInt(10, Faction.toInt(Faction.invalid));
helper.setInt(11, gameState.playByMail? 1 : 0);
helper.setString(12, gameState.actions);
helper.executeUpdate();
// Set id
ArrayList<Integer> generatedKeys = helper.getGeneratedKeys();
gameState.id = generatedKeys.get(0);
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Remove game from database
*
* @param id ID of the game to remove
* @throws SQLException
*/
public static void delete(int id) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
// Remove maps record
helper.prepareQuery("DELETE FROM games WHERE id=?");
helper.setInt(1, id);
helper.executeUpdate();
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Insert user that joined game in the database
*
* @param gameId Id of game
* @param faction Faction of the user
* @param userId Id of user that joined
*/
public static void joinGame(int gameId, int userId, Faction faction) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
// Create record
helper.prepareQuery("UPDATE games SET " + (faction == Faction.f1? "userId1" : "userId2") + "=? WHERE id=?");
helper.setInt(1, userId);
helper.setInt(2, gameId);
helper.executeUpdate();
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Mark a game as corrupt
*
* @param gameId Game Id of the game
*/
public static void markCorrupt(int gameId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
helper.prepareQuery("UPDATE games SET corrupt=1 WHERE id=?");
helper.setInt(1, gameId);
helper.executeUpdate();
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Load a game
*
* @param gameId Id of the game to load
* @return The game
* @throws SQLException
*/
public static GameState load(int gameId) throws SQLException, CacheException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
// Get record
helper.prepareQuery("SELECT countryConfigId, userId1, userId2, faction1IsRed, faction1Starts, lobbyId, attackedCountryX, attackedCountryY, defendedCountryX, defendedCountryY, playByMail, turnEndTime, corrupt, actions FROM games WHERE id=?");
helper.setInt(1, gameId);
helper.executeQuery();
if (!helper.nextRecord())
return null;
// Check corrupt
if (helper.getInt(13) != 0)
throw new RuntimeException("Trying to load corrupt game");
// Get country config
CountryConfig gc = CountryConfigCache.getInstance().get(helper.getInt(1));
// Create game state
GameState gameState = gc.createGameState(helper.getInt(4) != 0, helper.getInt(5) != 0, helper.getInt(6), helper.getInt(7), helper.getInt(8), helper.getInt(9), helper.getInt(10), helper.getInt(11) != 0, -1);
gameState.id = gameId;
gameState.turnEndTime = helper.getLong(12);
// Set users
int userId1 = helper.getInt(2);
if (userId1 > 0)
gameState.reJoinGame(Faction.f1, UserCache.getInstance().get(userId1));
int userId2 = helper.getInt(3);
if (userId2 > 0)
gameState.reJoinGame(Faction.f2, UserCache.getInstance().get(userId2));
// Execute actions
gameState.actions = helper.getString(14);
String actions[] = gameState.actions.split("\n");
for (String a : actions)
{
try
{
String[] params = a.split(",");
Action action = Action.createAction(params[0]);
action.setGameState(gameState);
action.fromString(params, null);
gameState.execute(action, false);
}
catch (IgnoreActionException e)
{
// Just ignore
}
catch (Exception e)
{
// Should normally not happen as the action was executed before
Tools.logException("Exception caught while loading game, "
+ "game: '" + gameId + "', "
+ "action: '" + a + "', exception: ", e);
// Mark this game as corrupt
try
{
markCorrupt(gameId);
}
catch (SQLException e2)
{
Tools.logException(e2);
}
// Wrap as SQL exception and throw it
throw new SQLException(e);
}
}
// Last action received is longer than the time out value, so set it to that
gameState.lastActionTime -= GameStateCache.TIME_OUT;
return gameState;
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Updates the state of the game in the database
*
* @param gameState The game state to update
* @throws SQLException
*/
public static void update(GameState gameState) throws SQLException
{
DbStoredProcHelper helper = new DbStoredProcHelper();
try
{
Score f1 = gameState.getScore(Faction.f1);
Score f2 = gameState.getScore(Faction.f2);
helper.prepareCall("{CALL updateGame(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}");
helper.setString(1, gameState.actions);
helper.setLong(2, gameState.turnEndTime);
helper.setInt(3, gameState.turnNumber);
helper.setInt(4, (gameState.canPerformAction(Faction.f1)? 1 : 0) + (gameState.canPerformAction(Faction.f2)? 2 : 0));
helper.setInt(5, Faction.toInt(gameState.winningFaction));
helper.setInt(6, f1.getTotalScore());
helper.setInt(7, f2.getTotalScore());
helper.setInt(8, f1.numberOfUnitsDestroyed + f1.numberOfBasesDestroyed);
helper.setInt(9, f2.numberOfUnitsDestroyed + f2.numberOfBasesDestroyed);
helper.setLong(10, Calendar.getInstance().getTime().getTime());
helper.setInt(11, gameState.id);
helper.execute();
}
finally
{
// Close database connection
helper.close();
}
}
/**
* Get game results by country
*/
public static int getGamesRequiringAttentionCount(int userId) throws SQLException
{
DbQueryHelper helper = new DbQueryHelper();
try
{
helper.prepareQuery("SELECT COUNT(1) FROM games WHERE ((userId1=? AND (currentPlayer & 1) <> 0) OR (userId2=? AND (currentPlayer & 2) <> 0)) AND winningFaction=? AND corrupt=0");
helper.setInt(1, userId);
helper.setInt(2, userId);
helper.setInt(3, Faction.toInt(Faction.invalid));
helper.executeQuery();
if (helper.nextRecord())
return helper.getInt(1);
else
return 0;
}
finally
{
// Close database connection
helper.close();
}
}
}