Improvements player cancels or leaves match or tournament. Draft can replace human player by draft bot if human leaves.

This commit is contained in:
LevelX2 2013-10-03 22:42:16 +02:00
parent 089fbf15b1
commit e2532a9b11
18 changed files with 300 additions and 102 deletions

View file

@ -44,6 +44,7 @@ import mage.cards.decks.DeckCardLists;
import mage.cards.decks.InvalidDeckException;
import mage.game.GameException;
import mage.game.GameOptions;
import mage.game.GameState;
import mage.game.Seat;
import mage.game.Table;
import mage.game.draft.Draft;
@ -56,6 +57,7 @@ import mage.game.match.MatchPlayer;
import mage.game.tournament.Tournament;
import mage.game.tournament.TournamentOptions;
import mage.game.tournament.TournamentPlayer;
import mage.interfaces.callback.ClientCallback;
import mage.players.Player;
import mage.server.challenge.ChallengeManager;
import mage.server.draft.DraftManager;
@ -66,6 +68,7 @@ import mage.server.tournament.TournamentFactory;
import mage.server.tournament.TournamentManager;
import mage.server.util.ServerMessagesUtil;
import mage.server.util.ThreadExecutor;
import mage.view.GameEndView;
import org.apache.log4j.Logger;
@ -175,6 +178,22 @@ public class TableController {
}
}
public synchronized boolean replaceDraftPlayer(Player oldPlayer, String name, String playerType, int skill) {
Player newPlayer = createPlayer(name, playerType, skill);
if (newPlayer == null || table.getState() != TableState.DRAFTING) {
return false;
}
TournamentPlayer oldTournamentPlayer = tournament.getPlayer(oldPlayer.getId());
tournament.removePlayer(oldPlayer.getId());
tournament.addPlayer(newPlayer, playerType);
TournamentPlayer newTournamentPlayer = tournament.getPlayer(newPlayer.getId());
newTournamentPlayer.setState(oldTournamentPlayer.getState());
DraftManager.getInstance().getController(table.getId()).replacePlayer(oldPlayer, newPlayer);
return true;
}
public synchronized boolean joinTable(UUID userId, String name, String playerType, int skill, DeckCardLists deckList) throws MageException {
User user = UserManager.getInstance().getUser(userId);
if (user == null) {
@ -334,26 +353,29 @@ public class TableController {
return player;
}
public void kill(UUID userId) {
leaveTable(userId);
userPlayerMap.remove(userId);
}
public synchronized void leaveTable(UUID userId) {
if (table.getState() == TableState.WAITING || table.getState() == TableState.STARTING) {
UUID playerId = userPlayerMap.get(userId);
if (playerId != null) {
table.leaveTable(playerId);
UUID playerId = userPlayerMap.get(userId);
if (playerId != null) {
if (table.getState() == TableState.WAITING || table.getState() == TableState.STARTING) {
table.leaveNotStartedTable(playerId);
if (table.isTournament()) {
tournament.leave(playerId);
TournamentManager.getInstance().quit(tournament.getId(), userId);
} else {
match.leave(playerId);
}
User user = UserManager.getInstance().getUser(userId);
user.removeTable(playerId);
userPlayerMap.remove(userId);
}
} else if (!table.getState().equals(TableState.FINISHED)) {
if (table.isTournament()) {
TableManager.getInstance().userQuitTournamentSubTables(userId);
TournamentManager.getInstance().quit(tournament.getId(), userId);
} else {
match.leave(playerId);
}
}
}
}
public synchronized void startMatch(UUID userId) {
@ -497,6 +519,30 @@ public class TableController {
}
}
private void sendMatchEndInfo(UUID playerId) {
for (Entry<UUID, UUID> entry: userPlayerMap.entrySet()) {
if (entry.getValue().equals(playerId)) {
User user = UserManager.getInstance().getUser(entry.getKey());
if (user != null) {
StringBuilder sb = new StringBuilder();
if (table.isTournamentSubTable()) {
sb.append("Your tournament match of round ");
sb.append(table.getTournament().getRounds().size());
sb.append(" is over. ");
} else {
sb.append("Match [").append(match.getName()).append("] is over. ");
}
if(match.getPlayers().size() > 2) {
sb.append("All your opponents have lost or quit the match.");
} else {
sb.append("Your opponent has quit the match.");
}
user.showUserMessage("Match info", sb.toString());
}
break;
}
}
}
public int getRemainingTime() {
return (int) futureTimeout.getDelay(TimeUnit.SECONDS);
}
@ -533,7 +579,17 @@ public class TableController {
setupTimeout(Match.SIDEBOARD_TIME);
match.sideboard();
cancelTimeout();
startGame(choosingPlayerId);
if (!match.isMatchOver()) {
startGame(choosingPlayerId);
} else {
table.endGame();
// opponent(s) left during sideboarding
for (MatchPlayer mPlayer :match.getPlayers()) {
if(!mPlayer.hasQuit()) {
this.sendMatchEndInfo(mPlayer.getPlayer().getId());
}
}
}
}
else {
match.getGames().clear();

View file

@ -166,9 +166,12 @@ public class TableManager {
}
}
public void removeSession(UUID userId) {
// remove user from all tournament sub tables
public void userQuitTournamentSubTables(UUID userId) {
for (TableController controller: controllers.values()) {
controller.kill(userId);
if (controller.getTable().isTournamentSubTable()) {
controller.leaveTable(userId);
}
}
}
@ -190,6 +193,13 @@ public class TableManager {
public void leaveTable(UUID userId, UUID tableId) {
if (controllers.containsKey(tableId)) {
controllers.get(tableId).leaveTable(userId);
// table not started yet and user is he owner, remove the table
if (isTableOwner(tableId, userId)) {
if (getTable(tableId).getState().equals(TableState.WAITING)
|| getTable(tableId).getState().equals(TableState.STARTING)) {
removeTable(tableId);
}
}
}
}

View file

@ -293,14 +293,7 @@ public class User {
session.setKilled();
}
for (Entry<UUID, Table> entry: tables.entrySet()) {
entry.getValue().leaveTable(entry.getKey());
// remove tables here only, if the match or tournament did not start yet (states waiting/starting).
// all other situations have to lead to a fnished match / tournament where players left / conceded for which reasons ever
if (TableManager.getInstance().isTableOwner(entry.getValue().getId(), userId)
&& (entry.getValue().getState().equals(TableState.WAITING)
|| entry.getValue().getState().equals(TableState.STARTING))) {
TableManager.getInstance().removeTable(userId, entry.getValue().getId());
}
TableManager.getInstance().leaveTable(userId, entry.getValue().getId());
}
ChatManager.getInstance().removeUser(userId, reason);
}

View file

@ -120,10 +120,10 @@ public class UserManager {
public void removeUser(UUID userId, User.DisconnectReason reason) {
if (users.containsKey(userId)) {
logger.info("user removed " + userId);
logger.info("Remove user " + users.get(userId).getName() + ": " + userId + " Reason: " + reason.toString());
ChatManager.getInstance().removeUser(userId, reason);
ChatManager.getInstance().broadcast(userId, "has disconnected", MessageColor.BLACK);
users.get(userId).kill(User.DisconnectReason.Disconnected);
users.get(userId).kill(reason);
users.remove(userId);
}
}

View file

@ -38,6 +38,7 @@ import mage.game.draft.DraftPlayer;
import mage.game.events.Listener;
import mage.game.events.PlayerQueryEvent;
import mage.game.events.TableEvent;
import mage.players.Player;
import mage.server.TableManager;
import mage.server.UserManager;
import mage.server.game.GameController;
@ -129,6 +130,15 @@ public class DraftController {
checkStart();
}
public boolean replacePlayer(Player oldPlayer, Player newPlayer) {
if (draft.replacePlayer(oldPlayer, newPlayer)) {
draftSessions.get(oldPlayer.getId()).setKilled();
draftSessions.remove(oldPlayer.getId());
return true;
}
return false;
}
private synchronized void startDraft() {
for (final Entry<UUID, DraftSession> entry: draftSessions.entrySet()) {
if (!entry.getValue().init()) {
@ -212,4 +222,11 @@ public class DraftController {
}
}
public UUID getTableId() {
return tableId;
}
public void abortDraft() {
draft.setAbort(true);
}
}

View file

@ -84,4 +84,12 @@ public class DraftManager {
draftControllers.remove(draftId);
}
public DraftController getController(UUID tableId) {
for (DraftController controller: draftControllers.values()) {
if (controller.getTableId().equals(tableId)) {
return controller;
}
}
return null;
}
}

View file

@ -46,8 +46,11 @@ import mage.game.tournament.Tournament;
import mage.game.tournament.TournamentPairing;
import mage.game.tournament.TournamentPlayer;
import mage.server.ChatManager;
import mage.server.TableController;
import mage.server.TableManager;
import mage.server.User;
import mage.server.UserManager;
import mage.server.draft.DraftManager;
import mage.server.game.GamesRoomManager;
import mage.server.util.ThreadExecutor;
import mage.view.ChatMessage.MessageColor;
@ -71,6 +74,8 @@ public class TournamentController {
private ConcurrentHashMap<UUID, UUID> userPlayerMap = new ConcurrentHashMap<UUID, UUID>();
private ConcurrentHashMap<UUID, TournamentSession> tournamentSessions = new ConcurrentHashMap<UUID, TournamentSession>();
private boolean abort = false;
public TournamentController(Tournament tournament, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId) {
this.userPlayerMap = userPlayerMap;
chatId = ChatManager.getInstance().createChatSession();
@ -93,16 +98,18 @@ public class TournamentController {
startDraft(event.getDraft());
break;
case CONSTRUCT:
construct();
if (!abort) {
construct();
} else {
endTournament();
}
break;
case START_MATCH:
initTournament(); // set state
startMatch(event.getPair(), event.getMatchOptions());
if (!abort) {
initTournament(); // set state
startMatch(event.getPair(), event.getMatchOptions());
}
break;
// case SUBMIT_DECK:
// submitDeck(event.getPlayerId(), event.getDeck());
// break;
case END:
endTournament();
break;
@ -265,37 +272,57 @@ public class TournamentController {
public void quit(UUID userId) {
UUID playerId = userPlayerMap.get(userId);
if (playerId != null) {
TournamentPlayer player = tournament.getPlayer(playerId);
if (player != null) {
ChatManager.getInstance().broadcast(chatId, "", player.getPlayer().getName() + " has quit the tournament", MessageColor.BLACK, true, SoundToPlay.PlayerLeft);
String info;
if (tournament.isDoneConstructing()) {
info = new StringBuilder("during round ").append(tournament.getRounds().size()).toString();
TournamentPlayer tPlayer = tournament.getPlayer(playerId);
if (tPlayer != null) {
if (started) {
ChatManager.getInstance().broadcast(chatId, "", tPlayer.getPlayer().getName() + " has quit the tournament", MessageColor.BLACK, true, SoundToPlay.PlayerLeft);
String info;
if (tournament.isDoneConstructing()) {
info = new StringBuilder("during round ").append(tournament.getRounds().size()).toString();
} else {
if (tPlayer.getState().equals(TournamentPlayerState.DRAFTING)) {
info = "during Draft phase";
if (!checkToReplaceDraftPlayerByAi(userId, tPlayer)) {
this.abortTournament();
}
} else if (tPlayer.getState().equals(TournamentPlayerState.CONSTRUCTING)) {
info = "during Construction phase";
} else {
info = "";
}
}
tPlayer.setQuit(info);
tournament.quit(playerId);
} else {
info = "during Construction phase";
tournament.leave(playerId);
}
player.setQuit(info);
tournament.quit(playerId);
}
}
}
public void kill(UUID userId) {
quit(userId);
// if (userPlayerMap.containsKey(userId)) {
// tournamentSessions.get(userPlayerMap.get(userId)).setKilled();
// tournamentSessions.remove(userPlayerMap.get(userId));
// leave(userId);
// userPlayerMap.remove(userId);
// }
}
private boolean checkToReplaceDraftPlayerByAi(UUID userId, TournamentPlayer leavingPlayer) {
private void leave(UUID userId) {
tournament.leave(getPlayerId(userId));
}
private UUID getPlayerId(UUID userId) {
return userPlayerMap.get(userId);
int humans = 0;
for (TournamentPlayer tPlayer :tournament.getPlayers()) {
if (tPlayer.getPlayer().isHuman()) {
humans++;
}
}
// replace player that quits with draft bot
if (humans > 1) {
String replacePlayerName = "Draftbot";
User user = UserManager.getInstance().getUser(userId);
if (user != null) {
replacePlayerName = "Draftbot (" + user.getName() + ")";
}
TableController tableController = TableManager.getInstance().getController(tableId);
if (tableController != null) {
tableController.replaceDraftPlayer(leavingPlayer.getPlayer(), replacePlayerName, "Computer - draftbot", 5);
ChatManager.getInstance().broadcast(chatId, "", leavingPlayer.getPlayer().getName() + " was replaced by draftbot", MessageColor.BLACK, true, null);
}
return true;
}
return false;
}
private UUID getPlayerSessionId(UUID playerId) {
@ -311,4 +338,8 @@ public class TournamentController {
return new TournamentView(tournament);
}
private void abortTournament() {
this.abort = true;
DraftManager.getInstance().getController(tableId).abortDraft();
}
}

View file

@ -48,6 +48,10 @@ public class TournamentManager {
return INSTANCE;
}
public TournamentController getTournamentController(UUID tournamentId) {
return controllers.get(tournamentId);
}
public void createTournamentSession(Tournament tournament, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId) {
TournamentController tournamentController = new TournamentController(tournament, userPlayerMap, tableId);
controllers.put(tournament.getId(), tournamentController);
@ -63,7 +67,7 @@ public class TournamentManager {
public void kill(UUID tournamentId, UUID userId) {
controllers.get(tournamentId).kill(userId);
controllers.get(tournamentId).quit(userId);
}
public void timeout(UUID tournamentId, UUID userId) {

View file

@ -121,7 +121,6 @@ public class TournamentSession {
public void setKilled() {
killed = true;
TournamentManager.getInstance().kill(tournament.getId(), userId);
}
private synchronized void setupTimeout(int seconds) {