Adding clocks on server side and cleaning up finished games after 5 minutes.
This commit is contained in:
@@ -5,6 +5,7 @@ import com.gempukku.lotro.logic.decisions.AwaitingDecision;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class DefaultUserFeedback implements UserFeedback {
|
public class DefaultUserFeedback implements UserFeedback {
|
||||||
private Map<String, AwaitingDecision> _awaitingDecisionMap = new HashMap<String, AwaitingDecision>();
|
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) {
|
public void sendWarning(String playerId, String warning) {
|
||||||
_warnings.put(playerId, warning);
|
_warnings.put(playerId, warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getUsersPendingDecision() {
|
||||||
|
return _awaitingDecisionMap.keySet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ public class LotroGameMediator {
|
|||||||
private Map<String, GatheringParticipantCommunicationChannel> _communicationChannels = new HashMap<String, GatheringParticipantCommunicationChannel>();
|
private Map<String, GatheringParticipantCommunicationChannel> _communicationChannels = new HashMap<String, GatheringParticipantCommunicationChannel>();
|
||||||
private DefaultUserFeedback _userFeedback = new DefaultUserFeedback();
|
private DefaultUserFeedback _userFeedback = new DefaultUserFeedback();
|
||||||
private DefaultLotroGame _lotroGame;
|
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) {
|
public LotroGameMediator(LotroFormat lotroFormat, LotroGameParticipant[] participants, LotroCardBlueprintLibrary library, GameResultListener gameResultListener) {
|
||||||
if (participants.length < 1)
|
if (participants.length < 1)
|
||||||
@@ -31,6 +34,7 @@ public class LotroGameMediator {
|
|||||||
String participantId = participant.getPlayerId();
|
String participantId = participant.getPlayerId();
|
||||||
participantSet.add(participantId);
|
participantSet.add(participantId);
|
||||||
decks.put(participantId, participant.getDeck());
|
decks.put(participantId, participant.getDeck());
|
||||||
|
_playerClocks.put(participantId, 0);
|
||||||
}
|
}
|
||||||
_lotroGame = new DefaultLotroGame(decks, _userFeedback, gameResultListener, library);
|
_lotroGame = new DefaultLotroGame(decks, _userFeedback, gameResultListener, library);
|
||||||
}
|
}
|
||||||
@@ -78,7 +82,13 @@ public class LotroGameMediator {
|
|||||||
try {
|
try {
|
||||||
_userFeedback.participantDecided(lotroGameParticipant);
|
_userFeedback.participantDecided(lotroGameParticipant);
|
||||||
awaitingDecision.decisionMade(answer);
|
awaitingDecision.decisionMade(answer);
|
||||||
|
|
||||||
|
// Decision successfully made, add the time to user clock
|
||||||
|
addTimeSpentOnDecisionToUserClock(lotroGameParticipant);
|
||||||
|
|
||||||
_lotroGame.carryOutPendingActionsUntilDecisionNeeded();
|
_lotroGame.carryOutPendingActionsUntilDecisionNeeded();
|
||||||
|
startClocksForUsersPendingDecision();
|
||||||
|
|
||||||
} catch (DecisionResultInvalidException decisionResultInvalidException) {
|
} catch (DecisionResultInvalidException decisionResultInvalidException) {
|
||||||
// Participant provided wrong answer - send a warning message, and ask again for the same decision
|
// Participant provided wrong answer - send a warning message, and ask again for the same decision
|
||||||
// _userCommunication.sendWarning(lotroGameParticipant, decisionResultInvalidException.getWarningMessage());
|
// _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) {
|
public synchronized void processCommunicationChannel(String participantId, ParticipantCommunicationVisitor visitor) {
|
||||||
GatheringParticipantCommunicationChannel communicationChannel = _communicationChannels.get(participantId);
|
GatheringParticipantCommunicationChannel communicationChannel = _communicationChannels.get(participantId);
|
||||||
if (communicationChannel != null)
|
if (communicationChannel != null)
|
||||||
@@ -99,6 +131,13 @@ public class LotroGameMediator {
|
|||||||
AwaitingDecision awaitingDecision = _userFeedback.getAwaitingDecision(participantId);
|
AwaitingDecision awaitingDecision = _userFeedback.getAwaitingDecision(participantId);
|
||||||
if (awaitingDecision != null)
|
if (awaitingDecision != null)
|
||||||
visitor.visitAwaitingDecision(_lotroGame.getActionStack().getTopmostAction(), awaitingDecision);
|
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) {
|
public synchronized void singupUserForGame(String participantId, ParticipantCommunicationVisitor visitor) {
|
||||||
@@ -116,5 +155,10 @@ public class LotroGameMediator {
|
|||||||
AwaitingDecision awaitingDecision = _userFeedback.getAwaitingDecision(participantId);
|
AwaitingDecision awaitingDecision = _userFeedback.getAwaitingDecision(participantId);
|
||||||
if (awaitingDecision != null)
|
if (awaitingDecision != null)
|
||||||
visitor.visitAwaitingDecision(_lotroGame.getActionStack().getTopmostAction(), awaitingDecision);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,17 @@ import com.gempukku.lotro.logic.vo.LotroDeck;
|
|||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class LotroServer {
|
public class LotroServer {
|
||||||
private static final Logger log = Logger.getLogger(LotroServer.class);
|
private static final Logger log = Logger.getLogger(LotroServer.class);
|
||||||
|
|
||||||
private LotroCardBlueprintLibrary _lotroCardBlueprintLibrary = new LotroCardBlueprintLibrary();
|
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 boolean _started;
|
||||||
private CleaningTask _cleaningTask;
|
private CleaningTask _cleaningTask;
|
||||||
@@ -83,21 +87,41 @@ public class LotroServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void cleanup() {
|
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) {
|
public synchronized String createNewGame(LotroFormat lotroFormat, LotroGameParticipant[] participants) {
|
||||||
if (participants.length < 2)
|
if (participants.length < 2)
|
||||||
throw new IllegalArgumentException("There has to be at least two players");
|
throw new IllegalArgumentException("There has to be at least two players");
|
||||||
String gameId = String.valueOf(_nextGameId);
|
final String gameId = String.valueOf(_nextGameId);
|
||||||
final String chatRoomName = "Game" + gameId;
|
String chatRoomName = getChatRoomName(gameId);
|
||||||
|
|
||||||
_chatServer.createChatRoom(chatRoomName);
|
_chatServer.createChatRoom(chatRoomName);
|
||||||
LotroGameMediator lotroGameMediator = new LotroGameMediator(lotroFormat, participants, _lotroCardBlueprintLibrary,
|
LotroGameMediator lotroGameMediator = new LotroGameMediator(lotroFormat, participants, _lotroCardBlueprintLibrary,
|
||||||
new GameResultListener() {
|
new GameResultListener() {
|
||||||
@Override
|
@Override
|
||||||
public void gameFinished(String winnerPlayerId, Set<String> loserPlayerIds) {
|
public void gameFinished(String winnerPlayerId, Set<String> loserPlayerIds) {
|
||||||
_chatServer.destroyChatRoom(chatRoomName);
|
synchronized (_finishedGamesTime) {
|
||||||
|
_finishedGamesTime.put(gameId, new Date());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ import com.gempukku.lotro.GameEvent;
|
|||||||
import com.gempukku.lotro.logic.decisions.AwaitingDecision;
|
import com.gempukku.lotro.logic.decisions.AwaitingDecision;
|
||||||
import com.gempukku.lotro.logic.timing.Action;
|
import com.gempukku.lotro.logic.timing.Action;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public interface ParticipantCommunicationVisitor {
|
public interface ParticipantCommunicationVisitor {
|
||||||
|
public void visitClock(Map<String, Integer> secondsLeft);
|
||||||
|
|
||||||
public void visitWarning(String warning);
|
public void visitWarning(String warning);
|
||||||
|
|
||||||
public void visitAwaitingDecision(Action currentAction, AwaitingDecision awaitingDecision);
|
public void visitAwaitingDecision(Action currentAction, AwaitingDecision awaitingDecision);
|
||||||
|
|||||||
@@ -420,6 +420,23 @@ public class ServerResource {
|
|||||||
public void visitAwaitingDecision(Action currentAction, AwaitingDecision awaitingDecision) {
|
public void visitAwaitingDecision(Action currentAction, AwaitingDecision awaitingDecision) {
|
||||||
_element.appendChild(serializeDecision(_doc, currentAction, 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) {
|
private Node serializeDecision(Document doc, Action currentAction, AwaitingDecision decision) {
|
||||||
|
|||||||
Reference in New Issue
Block a user