Adding clocks on server side and cleaning up finished games after 5 minutes.

This commit is contained in:
marcins78@gmail.com
2011-09-13 11:07:35 +00:00
parent f7f1799c95
commit c434d4fbc0
5 changed files with 99 additions and 5 deletions

View File

@@ -5,6 +5,7 @@ import com.gempukku.lotro.logic.decisions.AwaitingDecision;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class DefaultUserFeedback implements UserFeedback {
private Map<String, AwaitingDecision> _awaitingDecisionMap = new HashMap<String, AwaitingDecision>();
@@ -36,4 +37,8 @@ public class DefaultUserFeedback implements UserFeedback {
public void sendWarning(String playerId, String warning) {
_warnings.put(playerId, warning);
}
public Set<String> getUsersPendingDecision() {
return _awaitingDecisionMap.keySet();
}
}

View File

@@ -18,6 +18,9 @@ public class LotroGameMediator {
private Map<String, GatheringParticipantCommunicationChannel> _communicationChannels = new HashMap<String, GatheringParticipantCommunicationChannel>();
private DefaultUserFeedback _userFeedback = new DefaultUserFeedback();
private DefaultLotroGame _lotroGame;
private Map<String, Integer> _playerClocks = new HashMap<String, Integer>();
private Map<String, Long> _decisionQuerySentTimes = new HashMap<String, Long>();
private final int _maxSecondsPerPlayer = 60 * 30; // 30 minutes
public LotroGameMediator(LotroFormat lotroFormat, LotroGameParticipant[] participants, LotroCardBlueprintLibrary library, GameResultListener gameResultListener) {
if (participants.length < 1)
@@ -31,6 +34,7 @@ public class LotroGameMediator {
String participantId = participant.getPlayerId();
participantSet.add(participantId);
decks.put(participantId, participant.getDeck());
_playerClocks.put(participantId, 0);
}
_lotroGame = new DefaultLotroGame(decks, _userFeedback, gameResultListener, library);
}
@@ -78,7 +82,13 @@ public class LotroGameMediator {
try {
_userFeedback.participantDecided(lotroGameParticipant);
awaitingDecision.decisionMade(answer);
// Decision successfully made, add the time to user clock
addTimeSpentOnDecisionToUserClock(lotroGameParticipant);
_lotroGame.carryOutPendingActionsUntilDecisionNeeded();
startClocksForUsersPendingDecision();
} catch (DecisionResultInvalidException decisionResultInvalidException) {
// Participant provided wrong answer - send a warning message, and ask again for the same decision
// _userCommunication.sendWarning(lotroGameParticipant, decisionResultInvalidException.getWarningMessage());
@@ -88,6 +98,28 @@ public class LotroGameMediator {
}
}
private void startClocksForUsersPendingDecision() {
long currentTime = System.currentTimeMillis();
Set<String> users = _userFeedback.getUsersPendingDecision();
for (String user : users)
_decisionQuerySentTimes.put(user, currentTime);
}
private void addTimeSpentOnDecisionToUserClock(String participantId) {
long queryTime = _decisionQuerySentTimes.remove(participantId);
long currentTime = System.currentTimeMillis();
long diffSec = (currentTime - queryTime) / 1000;
_playerClocks.put(participantId, _playerClocks.get(participantId) + (int) diffSec);
}
private int getCurrentUserPendingTime(String participantId) {
if (!_decisionQuerySentTimes.containsKey(participantId))
return 0;
long queryTime = _decisionQuerySentTimes.get(participantId);
long currentTime = System.currentTimeMillis();
return (int) ((currentTime - queryTime) / 1000);
}
public synchronized void processCommunicationChannel(String participantId, ParticipantCommunicationVisitor visitor) {
GatheringParticipantCommunicationChannel communicationChannel = _communicationChannels.get(participantId);
if (communicationChannel != null)
@@ -99,6 +131,13 @@ public class LotroGameMediator {
AwaitingDecision awaitingDecision = _userFeedback.getAwaitingDecision(participantId);
if (awaitingDecision != null)
visitor.visitAwaitingDecision(_lotroGame.getActionStack().getTopmostAction(), awaitingDecision);
Map<String, Integer> secondsLeft = new HashMap<String, Integer>();
for (Map.Entry<String, Integer> playerClock : _playerClocks.entrySet()) {
String player = playerClock.getKey();
secondsLeft.put(player, _maxSecondsPerPlayer - playerClock.getValue() - getCurrentUserPendingTime(player));
}
visitor.visitClock(secondsLeft);
}
public synchronized void singupUserForGame(String participantId, ParticipantCommunicationVisitor visitor) {
@@ -116,5 +155,10 @@ public class LotroGameMediator {
AwaitingDecision awaitingDecision = _userFeedback.getAwaitingDecision(participantId);
if (awaitingDecision != null)
visitor.visitAwaitingDecision(_lotroGame.getActionStack().getTopmostAction(), awaitingDecision);
Map<String, Integer> secondsLeft = new HashMap<String, Integer>();
for (Map.Entry<String, Integer> playerClock : _playerClocks.entrySet())
secondsLeft.put(playerClock.getKey(), _maxSecondsPerPlayer - playerClock.getValue());
visitor.visitClock(secondsLeft);
}
}

View File

@@ -14,13 +14,17 @@ import com.gempukku.lotro.logic.vo.LotroDeck;
import org.apache.log4j.Logger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class LotroServer {
private static final Logger log = Logger.getLogger(LotroServer.class);
private LotroCardBlueprintLibrary _lotroCardBlueprintLibrary = new LotroCardBlueprintLibrary();
private Map<String, LotroGameMediator> _runningGames = new HashMap<String, LotroGameMediator>();
private Map<String, LotroGameMediator> _runningGames = new ConcurrentHashMap<String, LotroGameMediator>();
private final Map<String, Date> _finishedGamesTime = new LinkedHashMap<String, Date>();
private final long _timeToGameDeath = 1000 * 60 * 5; // 5 minutes
private boolean _started;
private CleaningTask _cleaningTask;
@@ -83,21 +87,41 @@ public class LotroServer {
}
public void cleanup() {
// TODO
long currentTime = System.currentTimeMillis();
synchronized (_finishedGamesTime) {
LinkedHashMap<String, Date> copy = new LinkedHashMap<String, Date>(_finishedGamesTime);
for (Map.Entry<String, Date> finishedGame : copy.entrySet()) {
if (finishedGame.getValue().getTime() > currentTime + _timeToGameDeath) {
String gameId = finishedGame.getKey();
_runningGames.remove(gameId);
_chatServer.destroyChatRoom(getChatRoomName(gameId));
_finishedGamesTime.remove(gameId);
} else {
break;
}
}
}
}
private String getChatRoomName(String gameId) {
return "Game" + gameId;
}
public synchronized String createNewGame(LotroFormat lotroFormat, LotroGameParticipant[] participants) {
if (participants.length < 2)
throw new IllegalArgumentException("There has to be at least two players");
String gameId = String.valueOf(_nextGameId);
final String chatRoomName = "Game" + gameId;
final String gameId = String.valueOf(_nextGameId);
String chatRoomName = getChatRoomName(gameId);
_chatServer.createChatRoom(chatRoomName);
LotroGameMediator lotroGameMediator = new LotroGameMediator(lotroFormat, participants, _lotroCardBlueprintLibrary,
new GameResultListener() {
@Override
public void gameFinished(String winnerPlayerId, Set<String> loserPlayerIds) {
_chatServer.destroyChatRoom(chatRoomName);
synchronized (_finishedGamesTime) {
_finishedGamesTime.put(gameId, new Date());
}
}
});

View File

@@ -4,7 +4,11 @@ import com.gempukku.lotro.GameEvent;
import com.gempukku.lotro.logic.decisions.AwaitingDecision;
import com.gempukku.lotro.logic.timing.Action;
import java.util.Map;
public interface ParticipantCommunicationVisitor {
public void visitClock(Map<String, Integer> secondsLeft);
public void visitWarning(String warning);
public void visitAwaitingDecision(Action currentAction, AwaitingDecision awaitingDecision);

View File

@@ -420,6 +420,23 @@ public class ServerResource {
public void visitAwaitingDecision(Action currentAction, AwaitingDecision awaitingDecision) {
_element.appendChild(serializeDecision(_doc, currentAction, awaitingDecision));
}
@Override
public void visitClock(Map<String, Integer> secondsLeft) {
_element.appendChild(serializeClocks(_doc, secondsLeft));
}
}
private Node serializeClocks(Document doc, Map<String, Integer> secondsLeft) {
Element clocks = doc.createElement("clocks");
for (Map.Entry<String, Integer> userClock : secondsLeft.entrySet()) {
Element clock = doc.createElement("clock");
clock.setAttribute("participantId", userClock.getKey());
clock.appendChild(doc.createTextNode(userClock.getValue().toString()));
clocks.appendChild(clock);
}
return clocks;
}
private Node serializeDecision(Document doc, Action currentAction, AwaitingDecision decision) {