Some changes to game end handling (in hope to fix/improve server handling of games). Some chanmges to log messages.

This commit is contained in:
LevelX2 2014-08-17 02:49:21 +02:00
parent c449a9b2fd
commit 0c03ce3727
4 changed files with 67 additions and 66 deletions

View file

@ -174,15 +174,17 @@ public class SessionManager {
} }
public User getUser(String sessionId) { public User getUser(String sessionId) {
if (sessions.containsKey(sessionId)) { Session session = sessions.get(sessionId);
if (session != null) {
return UserManager.getInstance().getUser(sessions.get(sessionId).getUserId()); return UserManager.getInstance().getUser(sessions.get(sessionId).getUserId());
} }
return null; return null;
} }
public boolean extendUserSession(String sessionId) { public boolean extendUserSession(String sessionId) {
if (sessions.containsKey(sessionId)) { Session session = sessions.get(sessionId);
return UserManager.getInstance().extendUserSession(sessions.get(sessionId).getUserId()); if (session != null) {
return UserManager.getInstance().extendUserSession(session.getUserId());
} }
return false; return false;
} }

View file

@ -276,8 +276,10 @@ public class GameSession extends GameWatcher {
public void kill() { public void kill() {
if (game != null) { if (game != null) {
logger.debug("before game.quit playerId:" + playerId); if (game.getPlayer(playerId).isInGame()) {
game.quit(playerId); logger.debug("QUIT game playerId: " + playerId + " gameId: " + game.getId());
game.quit(playerId);
}
} else { } else {
logger.error("game object missing playerId: " + (playerId == null ? "[null]":playerId)); logger.error("game object missing playerId: " + (playerId == null ? "[null]":playerId));
} }

View file

@ -118,7 +118,7 @@ public abstract class GameImpl implements Game, Serializable {
private static Random rnd = new Random(); private static Random rnd = new Random();
private transient Object customData; private transient Object customData;
protected boolean simulation = false; protected boolean simulation = false;
@ -127,7 +127,7 @@ public abstract class GameImpl implements Game, Serializable {
protected transient TableEventSource tableEventSource = new TableEventSource(); protected transient TableEventSource tableEventSource = new TableEventSource();
protected transient PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource(); protected transient PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource();
protected Map<UUID, Card> gameCards = new HashMap<>(); protected Map<UUID, Card> gameCards = new HashMap<>();
protected Map<Zone,HashMap<UUID, MageObject>> lki = new EnumMap<>(Zone.class); protected Map<Zone,HashMap<UUID, MageObject>> lki = new EnumMap<>(Zone.class);
protected Map<Zone,HashMap<UUID, MageObject>> shortLivingLKI = new EnumMap<>(Zone.class); protected Map<Zone,HashMap<UUID, MageObject>> shortLivingLKI = new EnumMap<>(Zone.class);
@ -436,7 +436,7 @@ public abstract class GameImpl implements Game, Serializable {
} }
} }
private boolean checkIfGameIsOver() { private boolean checkIfGameIsOver() {
if (state.isGameOver()) { if (state.isGameOver()) {
return true; return true;
@ -458,7 +458,7 @@ public abstract class GameImpl implements Game, Serializable {
logger.debug(new StringBuilder("Player ").append(player.getName()).append(" has won gameId: ").append(this.getId())); logger.debug(new StringBuilder("Player ").append(player.getName()).append(" has won gameId: ").append(this.getId()));
player.won(this); player.won(this);
} }
} }
return true; return true;
} }
return false; return false;
@ -473,7 +473,7 @@ public abstract class GameImpl implements Game, Serializable {
public boolean isADraw() { public boolean isADraw() {
return hasEnded() && winnerId == null; return hasEnded() && winnerId == null;
} }
@Override @Override
public String getWinner() { public String getWinner() {
if (winnerId == null) { if (winnerId == null) {
@ -705,7 +705,7 @@ public abstract class GameImpl implements Game, Serializable {
if (choosingPlayer == null) { if (choosingPlayer == null) {
choosingPlayer = getPlayer(pickChoosingPlayer()); choosingPlayer = getPlayer(pickChoosingPlayer());
} }
if (choosingPlayer != null && choosingPlayer.choose(Outcome.Benefit, targetPlayer, null, this)) { if (choosingPlayer != null && choosingPlayer.choose(Outcome.Benefit, targetPlayer, null, this)) {
startingPlayerId = ((List<UUID>)targetPlayer.getTargets()).get(0); startingPlayerId = ((List<UUID>)targetPlayer.getTargets()).get(0);
Player startingPlayer = state.getPlayer(startingPlayerId); Player startingPlayer = state.getPlayer(startingPlayerId);
@ -716,7 +716,7 @@ public abstract class GameImpl implements Game, Serializable {
message.append(startingPlayer.getName()); message.append(startingPlayer.getName());
} }
message.append(" takes the first turn"); message.append(" takes the first turn");
this.informPlayers(message.toString()); this.informPlayers(message.toString());
} else { } else {
// not possible to choose starting player, stop here // not possible to choose starting player, stop here
@ -901,7 +901,7 @@ public abstract class GameImpl implements Game, Serializable {
@Override @Override
public void endMulligan(UUID playerId){ public void endMulligan(UUID playerId){
} }
@Override @Override
public void mulligan(UUID playerId) { public void mulligan(UUID playerId) {
Player player = getPlayer(playerId); Player player = getPlayer(playerId);
@ -912,14 +912,14 @@ public abstract class GameImpl implements Game, Serializable {
int deduction = 1; int deduction = 1;
if (freeMulligans > 0) { if (freeMulligans > 0) {
if (usedFreeMulligans != null && usedFreeMulligans.containsKey(player.getId())) { if (usedFreeMulligans != null && usedFreeMulligans.containsKey(player.getId())) {
int used = usedFreeMulligans.get(player.getId()).intValue(); int used = usedFreeMulligans.get(player.getId());
if (used < freeMulligans ) { if (used < freeMulligans ) {
deduction = 0; deduction = 0;
usedFreeMulligans.put(player.getId(), new Integer(used+1)); usedFreeMulligans.put(player.getId(), used+1);
} }
} else { } else {
deduction = 0; deduction = 0;
usedFreeMulligans.put(player.getId(), new Integer(1)); usedFreeMulligans.put(player.getId(), 1);
} }
} }
fireInformEvent(new StringBuilder(player.getName()) fireInformEvent(new StringBuilder(player.getName())
@ -931,20 +931,13 @@ public abstract class GameImpl implements Game, Serializable {
} }
@Override @Override
public synchronized void quit(UUID playerId) { public void quit(UUID playerId) {
logger.debug("GameImpl.quit start " + playerId);
if (state != null) { if (state != null) {
Player player = state.getPlayer(playerId); Player player = state.getPlayer(playerId);
if (player != null) { if (player != null) {
logger.debug("GameImpl.quit " + player.getName() + " quits the game");
player.quit(this); player.quit(this);
}else {
logger.error(new StringBuilder("GameImpl.quit - player not found - playerId: ").append(playerId));
} }
} else {
logger.error(new StringBuilder("GameImpl.quit - state not found - playerId: ").append(playerId));
} }
logger.debug("GameImpl.quit end " + playerId);
} }
@Override @Override
@ -1112,11 +1105,11 @@ public abstract class GameImpl implements Game, Serializable {
top = state.getStack().peek(); top = state.getStack().peek();
top.resolve(this); top.resolve(this);
} finally { } finally {
if (top != null) { if (top != null) {
if (!getTurn().isEndTurnRequested()) { if (!getTurn().isEndTurnRequested()) {
while (state.hasSimultaneousEvents()) { while (state.hasSimultaneousEvents()) {
state.handleSimultaneousEvent(this); state.handleSimultaneousEvent(this);
checkTriggered(); checkTriggered();
} }
} }
state.getStack().remove(top); state.getStack().remove(top);
@ -1182,8 +1175,8 @@ public abstract class GameImpl implements Game, Serializable {
} }
state.addCommandObject(newEmblem); state.addCommandObject(newEmblem);
} }
@Override @Override
public void addCommander(Commander commander){ public void addCommander(Commander commander){
state.addCommandObject(commander); state.addCommandObject(commander);
@ -1294,7 +1287,12 @@ public abstract class GameImpl implements Game, Serializable {
} }
return somethingHappened; return somethingHappened;
} }
/**
* Sets the waiting triggered abilities (if there are any)
* to the stack in the choosen order by player
*
* @return
*/
public boolean checkTriggered() { public boolean checkTriggered() {
boolean played = false; boolean played = false;
for (UUID playerId: state.getPlayerList(state.getActivePlayerId())) { for (UUID playerId: state.getPlayerList(state.getActivePlayerId())) {
@ -1311,7 +1309,7 @@ public abstract class GameImpl implements Game, Serializable {
state.removeTriggeredAbility(triggeredAbility); state.removeTriggeredAbility(triggeredAbility);
played |= player.triggerAbility(triggeredAbility, this); played |= player.triggerAbility(triggeredAbility, this);
it.remove(); it.remove();
} }
} }
if (abilities.isEmpty()) { if (abilities.isEmpty()) {
break; break;
@ -1320,7 +1318,7 @@ public abstract class GameImpl implements Game, Serializable {
state.removeTriggeredAbility(abilities.get(0)); state.removeTriggeredAbility(abilities.get(0));
played |= player.triggerAbility(abilities.get(0), this); played |= player.triggerAbility(abilities.get(0), this);
} }
else { else {
TriggeredAbility ability = player.chooseTriggeredAbility(abilities, this); TriggeredAbility ability = player.chooseTriggeredAbility(abilities, this);
if (ability != null) { if (ability != null) {
state.removeTriggeredAbility(ability); state.removeTriggeredAbility(ability);
@ -1497,12 +1495,12 @@ public abstract class GameImpl implements Game, Serializable {
} }
} }
//20091005 - 704.5q If a creature is attached to an object or player, it becomes unattached and remains on the battlefield. //20091005 - 704.5q If a creature is attached to an object or player, it becomes unattached and remains on the battlefield.
// Similarly, if a permanent that’s neither an Aura, an Equipment, nor a Fortification is attached to an object or player, // Similarly, if a permanent that’s neither an Aura, an Equipment, nor a Fortification is attached to an object or player,
// it becomes unattached and remains on the battlefield. // it becomes unattached and remains on the battlefield.
if (perm.getAttachments().size() > 0) { if (perm.getAttachments().size() > 0) {
for (UUID attachmentId : perm.getAttachments()) { for (UUID attachmentId : perm.getAttachments()) {
Permanent attachment = getPermanent(attachmentId); Permanent attachment = getPermanent(attachmentId);
if (attachment != null && if (attachment != null &&
(attachment.getCardType().contains(CardType.CREATURE) || (attachment.getCardType().contains(CardType.CREATURE) ||
!(attachment.getSubtype().contains("Aura") !(attachment.getSubtype().contains("Aura")
|| attachment.getSubtype().contains("Equipment") || attachment.getSubtype().contains("Equipment")
@ -1599,9 +1597,9 @@ public abstract class GameImpl implements Game, Serializable {
.append(" is put into graveyard from battlefield").toString()); .append(" is put into graveyard from battlefield").toString());
result = true; result = true;
} }
return result; return result;
} }
@Override @Override
public void addPlayerQueryEventListener(Listener<PlayerQueryEvent> listener) { public void addPlayerQueryEventListener(Listener<PlayerQueryEvent> listener) {
playerQueryEventSource.addListener(listener); playerQueryEventSource.addListener(listener);
@ -1853,25 +1851,25 @@ public abstract class GameImpl implements Game, Serializable {
} }
/** /**
* 800.4a When a player leaves the game, all objects (see rule 109) owned by that player leave * 800.4a When a player leaves the game, all objects (see rule 109) owned by that player leave
* the game and any effects which give that player control of any objects or players end. Then, * the game and any effects which give that player control of any objects or players end. Then,
* if that player controlled any objects on the stack not represented by cards, those objects * if that player controlled any objects on the stack not represented by cards, those objects
* cease to exist. Then, if there are any objects still controlled by that player, those objects * cease to exist. Then, if there are any objects still controlled by that player, those objects
* are exiled. This is not a state-based action. It happens as soon as the player leaves the game. * are exiled. This is not a state-based action. It happens as soon as the player leaves the game.
* If the player who left the game had priority at the time he or she left, priority passes to * If the player who left the game had priority at the time he or she left, priority passes to
* the next player in turn order who's still in the game. # * the next player in turn order who's still in the game. #
* *
* @param playerId * @param playerId
*/ */
protected void leave(UUID playerId) { protected void leave(UUID playerId) {
Player player = getPlayer(playerId); Player player = getPlayer(playerId);
if (player == null || player.hasLeft()) { if (player == null || player.hasLeft()) {
logger.debug("game.leave -> player already left " + (player != null ? player.getName():playerId)); logger.debug("Player already left " + (player != null ? player.getName():playerId));
return; return;
} }
logger.debug("game.leave -> start player: " + player.getName()); logger.debug("Start leave game: " + player.getName());
player.leave(); player.leave();
if (checkIfGameIsOver()) { if (checkIfGameIsOver()) {
// no need to remove objects if only one player is left so the game is over // no need to remove objects if only one player is left so the game is over
@ -1924,7 +1922,7 @@ public abstract class GameImpl implements Game, Serializable {
Card card = entry.getValue(); Card card = entry.getValue();
if (card.getOwnerId().equals(playerId)) { if (card.getOwnerId().equals(playerId)) {
it.remove(); it.remove();
} }
} }
// Update players in range of // Update players in range of
@ -1978,7 +1976,7 @@ public abstract class GameImpl implements Game, Serializable {
result.setReplaced(true); result.setReplaced(true);
return result; return result;
} }
if (event.getAmount() > amountToPrevent) { if (event.getAmount() > amountToPrevent) {
result.setPreventedDamage(amountToPrevent); result.setPreventedDamage(amountToPrevent);
damageEvent.setAmount(event.getAmount() - amountToPrevent); damageEvent.setAmount(event.getAmount() - amountToPrevent);
@ -1986,11 +1984,11 @@ public abstract class GameImpl implements Game, Serializable {
result.setPreventedDamage(event.getAmount()); result.setPreventedDamage(event.getAmount());
damageEvent.setAmount(0); damageEvent.setAmount(0);
} }
if (amountToPrevent != Integer.MAX_VALUE) { if (amountToPrevent != Integer.MAX_VALUE) {
// set remaining amount // set remaining amount
result.setRemainingAmount(amountToPrevent -= result.getPreventedDamage()); result.setRemainingAmount(amountToPrevent -= result.getPreventedDamage());
} }
MageObject damageSource = game.getObject(damageEvent.getSourceId()); MageObject damageSource = game.getObject(damageEvent.getSourceId());
MageObject preventionSource = game.getObject(source.getSourceId()); MageObject preventionSource = game.getObject(source.getSourceId());
@ -2329,7 +2327,7 @@ public abstract class GameImpl implements Game, Serializable {
public void setScopeRelevant(boolean scopeRelevant) { public void setScopeRelevant(boolean scopeRelevant) {
this.scopeRelevant = scopeRelevant; this.scopeRelevant = scopeRelevant;
} }
/** /**
* @return - true if only self scope replacement effects have to be applied * @return - true if only self scope replacement effects have to be applied
*/ */
@ -2342,13 +2340,13 @@ public abstract class GameImpl implements Game, Serializable {
public boolean isSaveGame() { public boolean isSaveGame() {
return saveGame; return saveGame;
} }
@Override @Override
public void setSaveGame(boolean saveGame) { public void setSaveGame(boolean saveGame) {
this.saveGame = saveGame; this.saveGame = saveGame;
} }
public void setStartMessage(String startMessage) { public void setStartMessage(String startMessage) {
this.startMessage = startMessage; this.startMessage = startMessage;
} }

View file

@ -747,6 +747,7 @@ public abstract class PlayerImpl implements Player, Serializable {
castSourceIdWithoutMana = sourceId; castSourceIdWithoutMana = sourceId;
} }
@Override
public UUID getCastSourceIdWithoutMana() { public UUID getCastSourceIdWithoutMana() {
return castSourceIdWithoutMana; return castSourceIdWithoutMana;
} }
@ -1116,7 +1117,7 @@ public abstract class PlayerImpl implements Player, Serializable {
// create list of all "notMoreThan" effects to track which one are consumed // create list of all "notMoreThan" effects to track which one are consumed
HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffectsUsage = new HashMap<>(); HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffectsUsage = new HashMap<>();
for (Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> restrictionEffect: game.getContinuousEffects().getApplicableRestrictionUntapNotMoreThanEffects(this, game).entrySet()) { for (Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> restrictionEffect: game.getContinuousEffects().getApplicableRestrictionUntapNotMoreThanEffects(this, game).entrySet()) {
notMoreThanEffectsUsage.put(restrictionEffect, new Integer(restrictionEffect.getKey().getNumber())); notMoreThanEffectsUsage.put(restrictionEffect, restrictionEffect.getKey().getNumber());
} }
if (!notMoreThanEffectsUsage.isEmpty()) { if (!notMoreThanEffectsUsage.isEmpty()) {
@ -1141,7 +1142,7 @@ public abstract class PlayerImpl implements Player, Serializable {
// select permanents to untap to consume the "notMoreThan" effects // select permanents to untap to consume the "notMoreThan" effects
for(Map.Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> handledEntry: notMoreThanEffectsUsage.entrySet()) { for(Map.Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> handledEntry: notMoreThanEffectsUsage.entrySet()) {
// select a permanent to untap for this entry // select a permanent to untap for this entry
int numberToUntap = handledEntry.getValue().intValue(); int numberToUntap = handledEntry.getValue();
if (numberToUntap > 0) { if (numberToUntap > 0) {
List<Permanent> leftForUntap = getPermanentsThatCanBeUntapped(game, canBeUntapped, handledEntry.getKey().getKey(), notMoreThanEffectsUsage); List<Permanent> leftForUntap = getPermanentsThatCanBeUntapped(game, canBeUntapped, handledEntry.getKey().getKey(), notMoreThanEffectsUsage);
@ -1178,8 +1179,8 @@ public abstract class PlayerImpl implements Player, Serializable {
filter.add(Predicates.not(new PermanentIdPredicate(selectedPermanent.getId()))); filter.add(Predicates.not(new PermanentIdPredicate(selectedPermanent.getId())));
// reduce available untap numbers from other "UntapNotMoreThan" effects if selected permanent applies to their filter too // reduce available untap numbers from other "UntapNotMoreThan" effects if selected permanent applies to their filter too
for (Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) { for (Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) {
if (notMoreThanEffect.getValue().intValue() > 0 && notMoreThanEffect.getKey().getKey().getFilter().match(selectedPermanent, game)) { if (notMoreThanEffect.getValue() > 0 && notMoreThanEffect.getKey().getKey().getFilter().match(selectedPermanent, game)) {
notMoreThanEffect.setValue(new Integer(notMoreThanEffect.getValue().intValue() - 1)); notMoreThanEffect.setValue(notMoreThanEffect.getValue() - 1);
} }
} }
// update the left for untap list // update the left for untap list
@ -1250,7 +1251,7 @@ public abstract class PlayerImpl implements Player, Serializable {
boolean canBeSelected = true; boolean canBeSelected = true;
// check if the permanent is restriced by another restriction that has left no permanent // check if the permanent is restriced by another restriction that has left no permanent
for (Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) { for (Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) {
if (notMoreThanEffect.getKey().getKey().getFilter().match(permanent, game) && notMoreThanEffect.getValue().intValue() == 0) { if (notMoreThanEffect.getKey().getKey().getFilter().match(permanent, game) && notMoreThanEffect.getValue() == 0) {
canBeSelected = false; canBeSelected = false;
break; break;
} }
@ -1540,10 +1541,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public void quit(Game game) { public void quit(Game game) {
log.debug("PlayerImpl.quit start " + getName() + " quits game " + game.getId());
game.informPlayers(new StringBuilder(getName()).append(" quits the match.").toString()); game.informPlayers(new StringBuilder(getName()).append(" quits the match.").toString());
quit = true; quit = true;
log.debug("PlayerImpl.quit before concede" + getName() + " quits game " + game.getId());
this.concede(game); this.concede(game);
} }
@ -1614,21 +1613,21 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public void lost(Game game) { public void lost(Game game) {
log.debug("player lost -> start: " + this.getName()); log.debug(this.getName() + " has lost gameId: " + game.getId());
if (canLose(game)) { if (canLose(game)) {
this.loses = true;
//20100423 - 603.9 //20100423 - 603.9
if (!this.wins) { if (!this.wins) {
this.loses = true;
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST, null, null, playerId)); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LOST, null, null, playerId));
game.informPlayers(new StringBuilder(this.getName()).append(" has lost the game.").toString()); game.informPlayers(new StringBuilder(this.getName()).append(" has lost the game.").toString());
} else { } else {
log.debug("player.lost -> stop setting lost because he already has won!: " + this.getName()); log.debug(this.getName() + " has already won - stop lost");
}
// for draw - first all players that have lost have to be set to lost
if (!hasLeft()) {
log.debug("Game over playerId: " + playerId);
game.gameOver(playerId);
} }
// for draw first all players that have lost have to be set to lost
// if (!hasLeft()) {
// log.debug("player.lost -> calling leave");
// game.gameOver(playerId);
// }
} }
} }