Introducing HallServer (pairing players, etc).
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package com.gempukku.lotro;
|
||||
|
||||
public abstract class AbstractServer {
|
||||
private boolean _started;
|
||||
private CleaningTask _cleaningTask;
|
||||
|
||||
public final synchronized void startServer() {
|
||||
if (!_started) {
|
||||
_cleaningTask = new CleaningTask();
|
||||
new Thread(_cleaningTask).start();
|
||||
_started = true;
|
||||
}
|
||||
}
|
||||
|
||||
public final synchronized void stopServer() {
|
||||
if (_started) {
|
||||
_cleaningTask.stop();
|
||||
_started = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void cleanup();
|
||||
|
||||
private class CleaningTask implements Runnable {
|
||||
private boolean _running = true;
|
||||
|
||||
public void run() {
|
||||
while (_running) {
|
||||
cleanup();
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
_running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.gempukku.lotro.chat;
|
||||
|
||||
import com.gempukku.lotro.GatheringChatRoomListener;
|
||||
import com.gempukku.lotro.game.GatheringChatRoomListener;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package com.gempukku.lotro.chat;
|
||||
|
||||
import com.gempukku.lotro.AbstractServer;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ChatServer {
|
||||
public class ChatServer extends AbstractServer {
|
||||
private Map<String, ChatRoomMediator> _chatRooms = new ConcurrentHashMap<String, ChatRoomMediator>();
|
||||
|
||||
private boolean _started;
|
||||
private CleaningTask _cleaningTask;
|
||||
|
||||
public void createChatRoom(String name) {
|
||||
_chatRooms.put(name, new ChatRoomMediator());
|
||||
}
|
||||
@@ -21,42 +20,8 @@ public class ChatServer {
|
||||
_chatRooms.remove(name);
|
||||
}
|
||||
|
||||
public synchronized void startServer() {
|
||||
if (!_started) {
|
||||
_cleaningTask = new CleaningTask();
|
||||
new Thread(_cleaningTask).start();
|
||||
_started = true;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stopServer() {
|
||||
if (_started) {
|
||||
_cleaningTask.stop();
|
||||
_started = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
protected void cleanup() {
|
||||
for (ChatRoomMediator chatRoomMediator : _chatRooms.values())
|
||||
chatRoomMediator.cleanup();
|
||||
}
|
||||
|
||||
private class CleaningTask implements Runnable {
|
||||
private boolean _running = true;
|
||||
|
||||
public void run() {
|
||||
while (_running) {
|
||||
cleanup();
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
_running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.gempukku.lotro;
|
||||
package com.gempukku.lotro.game;
|
||||
|
||||
import com.gempukku.lotro.communication.UserFeedback;
|
||||
import com.gempukku.lotro.logic.decisions.AwaitingDecision;
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.gempukku.lotro;
|
||||
package com.gempukku.lotro.game;
|
||||
|
||||
import com.gempukku.lotro.common.CardType;
|
||||
import com.gempukku.lotro.common.Phase;
|
||||
import com.gempukku.lotro.common.Token;
|
||||
import com.gempukku.lotro.common.Zone;
|
||||
import com.gempukku.lotro.game.PhysicalCard;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.gempukku.lotro;
|
||||
package com.gempukku.lotro.game;
|
||||
|
||||
import com.gempukku.lotro.chat.ChatMessage;
|
||||
import com.gempukku.lotro.chat.ChatRoomListener;
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.gempukku.lotro;
|
||||
package com.gempukku.lotro.game;
|
||||
|
||||
import static com.gempukku.lotro.GameEvent.Type.*;
|
||||
import com.gempukku.lotro.common.Phase;
|
||||
import com.gempukku.lotro.common.Token;
|
||||
import com.gempukku.lotro.communication.GameStateListener;
|
||||
import com.gempukku.lotro.game.PhysicalCard;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.gempukku.lotro.game.GameEvent.Type.*;
|
||||
|
||||
public class GatheringParticipantCommunicationChannel implements GameStateListener {
|
||||
private List<GameEvent> _events = new LinkedList<GameEvent>();
|
||||
private String _self;
|
||||
@@ -1,10 +1,6 @@
|
||||
package com.gempukku.lotro;
|
||||
package com.gempukku.lotro.game;
|
||||
|
||||
import com.gempukku.lotro.common.CardType;
|
||||
import com.gempukku.lotro.game.LotroCardBlueprintLibrary;
|
||||
import com.gempukku.lotro.game.LotroFormat;
|
||||
import com.gempukku.lotro.game.ParticipantCommunicationVisitor;
|
||||
import com.gempukku.lotro.game.PhysicalCard;
|
||||
import com.gempukku.lotro.logic.decisions.AwaitingDecision;
|
||||
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
|
||||
import com.gempukku.lotro.logic.modifiers.Modifier;
|
||||
@@ -12,10 +8,7 @@ import com.gempukku.lotro.logic.timing.DefaultLotroGame;
|
||||
import com.gempukku.lotro.logic.timing.GameResultListener;
|
||||
import com.gempukku.lotro.logic.vo.LotroDeck;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class LotroGameMediator {
|
||||
private Map<String, GatheringParticipantCommunicationChannel> _communicationChannels = new HashMap<String, GatheringParticipantCommunicationChannel>();
|
||||
@@ -23,6 +16,7 @@ public class LotroGameMediator {
|
||||
private DefaultLotroGame _lotroGame;
|
||||
private Map<String, Integer> _playerClocks = new HashMap<String, Integer>();
|
||||
private Map<String, Long> _decisionQuerySentTimes = new HashMap<String, Long>();
|
||||
private Set<String> _playersPlaying = new HashSet<String>();
|
||||
|
||||
private final int _maxSecondsForGamePerPlayer = 60 * 30; // 30 minutes
|
||||
private final int _channelInactivityTimeoutPeriod = 1000 * 60 * 5; // 5 minutes
|
||||
@@ -40,10 +34,15 @@ public class LotroGameMediator {
|
||||
String participantId = participant.getPlayerId();
|
||||
decks.put(participantId, participant.getDeck());
|
||||
_playerClocks.put(participantId, 0);
|
||||
_playersPlaying.add(participantId);
|
||||
}
|
||||
_lotroGame = new DefaultLotroGame(decks, _userFeedback, gameResultListener, library);
|
||||
}
|
||||
|
||||
public Set<String> getPlayersPlaying() {
|
||||
return Collections.unmodifiableSet(_playersPlaying);
|
||||
}
|
||||
|
||||
public synchronized String produceCardInfo(String participantId, int cardId) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.gempukku.lotro;
|
||||
package com.gempukku.lotro.game;
|
||||
|
||||
import com.gempukku.lotro.logic.vo.LotroDeck;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.gempukku.lotro;
|
||||
package com.gempukku.lotro.game;
|
||||
|
||||
import com.gempukku.lotro.AbstractServer;
|
||||
import com.gempukku.lotro.chat.ChatServer;
|
||||
import com.gempukku.lotro.common.CardType;
|
||||
import com.gempukku.lotro.common.Keyword;
|
||||
@@ -8,7 +9,6 @@ import com.gempukku.lotro.db.DeckDAO;
|
||||
import com.gempukku.lotro.db.PlayerDAO;
|
||||
import com.gempukku.lotro.db.vo.Deck;
|
||||
import com.gempukku.lotro.db.vo.Player;
|
||||
import com.gempukku.lotro.game.*;
|
||||
import com.gempukku.lotro.logic.timing.GameResultListener;
|
||||
import com.gempukku.lotro.logic.vo.LotroDeck;
|
||||
import org.apache.log4j.Logger;
|
||||
@@ -16,18 +16,17 @@ import org.apache.log4j.Logger;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class LotroServer {
|
||||
public class LotroServer extends AbstractServer {
|
||||
private static final Logger log = Logger.getLogger(LotroServer.class);
|
||||
|
||||
private LotroCardBlueprintLibrary _lotroCardBlueprintLibrary = new LotroCardBlueprintLibrary();
|
||||
|
||||
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;
|
||||
private int _nextGameId = 1;
|
||||
|
||||
private PlayerDAO _playerDao;
|
||||
@@ -71,22 +70,7 @@ public class LotroServer {
|
||||
return _defaultCollection;
|
||||
}
|
||||
|
||||
public synchronized void startServer() {
|
||||
if (!_started) {
|
||||
_cleaningTask = new CleaningTask();
|
||||
new Thread(_cleaningTask).start();
|
||||
_started = true;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stopServer() {
|
||||
if (_started) {
|
||||
_cleaningTask.stop();
|
||||
_started = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
protected void cleanup() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
synchronized (_finishedGamesTime) {
|
||||
@@ -186,23 +170,4 @@ public class LotroServer {
|
||||
public LotroGameMediator getGameById(String gameId) {
|
||||
return _runningGames.get(gameId);
|
||||
}
|
||||
|
||||
private class CleaningTask implements Runnable {
|
||||
private boolean _running = true;
|
||||
|
||||
public void run() {
|
||||
while (_running) {
|
||||
cleanup();
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("Cleaning task interrupted", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
_running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.gempukku.lotro.game;
|
||||
|
||||
import com.gempukku.lotro.GameEvent;
|
||||
import com.gempukku.lotro.logic.decisions.AwaitingDecision;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.gempukku.lotro.hall;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class AwaitingTable {
|
||||
private Set<String> _players = new HashSet<String>();
|
||||
|
||||
private int _capacity = 2;
|
||||
|
||||
public boolean addPlayer(String playerId) {
|
||||
_players.add(playerId);
|
||||
return _players.size() == _capacity;
|
||||
}
|
||||
|
||||
public boolean removePlayer(String playerId) {
|
||||
_players.remove(playerId);
|
||||
return _players.size() == 0;
|
||||
}
|
||||
|
||||
public boolean hasPlayer(String playerId) {
|
||||
return _players.contains(playerId);
|
||||
}
|
||||
|
||||
public Set<String> getPlayers() {
|
||||
return Collections.unmodifiableSet(_players);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.gempukku.lotro.hall;
|
||||
|
||||
import com.gempukku.lotro.AbstractServer;
|
||||
import com.gempukku.lotro.chat.ChatServer;
|
||||
import com.gempukku.lotro.game.DefaultLotroFormat;
|
||||
import com.gempukku.lotro.game.LotroGameMediator;
|
||||
import com.gempukku.lotro.game.LotroGameParticipant;
|
||||
import com.gempukku.lotro.game.LotroServer;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class HallServer extends AbstractServer {
|
||||
private ChatServer _chatServer;
|
||||
private LotroServer _lotroServer;
|
||||
|
||||
private Map<String, AwaitingTable> _awaitingTables = new ConcurrentHashMap<String, AwaitingTable>();
|
||||
private Map<String, String> _runningTables = new ConcurrentHashMap<String, String>();
|
||||
private int _nextTableId = 1;
|
||||
|
||||
private final int _playerInactivityPeriod = 1000 * 10; // 10 seconds
|
||||
|
||||
private Map<String, Long> _lastVisitedPlayers = Collections.synchronizedMap(new LinkedHashMap<String, Long>());
|
||||
|
||||
public HallServer(LotroServer lotroServer, ChatServer chatServer) {
|
||||
_lotroServer = lotroServer;
|
||||
_chatServer = chatServer;
|
||||
_chatServer.createChatRoom("default");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param playerId
|
||||
* @return If table created, otherwise <code>false</code> (if the user already is sitting at a table or playing).
|
||||
*/
|
||||
public synchronized boolean createNewTable(String playerId) {
|
||||
if (isPlayerBusy(playerId))
|
||||
return false;
|
||||
|
||||
String tableId = String.valueOf(_nextTableId++);
|
||||
AwaitingTable table = new AwaitingTable();
|
||||
table.addPlayer(playerId);
|
||||
_awaitingTables.put(tableId, table);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param playerId
|
||||
* @return If table joined, otherwise <code>false</code> (if the user already is sitting at a table or playing).
|
||||
*/
|
||||
public synchronized boolean joinTableAsPlayer(String tableId, String playerId) {
|
||||
if (isPlayerBusy(playerId))
|
||||
return false;
|
||||
|
||||
AwaitingTable awaitingTable = _awaitingTables.get(tableId);
|
||||
if (awaitingTable == null)
|
||||
return false;
|
||||
boolean tableFull = awaitingTable.addPlayer(playerId);
|
||||
if (tableFull) {
|
||||
Set<String> players = awaitingTable.getPlayers();
|
||||
LotroGameParticipant[] participants = new LotroGameParticipant[players.size()];
|
||||
int index = 0;
|
||||
for (String player : players)
|
||||
participants[index] = new LotroGameParticipant(player, _lotroServer.getParticipantDeck(player));
|
||||
|
||||
String gameId = _lotroServer.createNewGame(new DefaultLotroFormat(true), participants);
|
||||
LotroGameMediator lotroGameMediator = _lotroServer.getGameById(gameId);
|
||||
lotroGameMediator.startGame();
|
||||
_runningTables.put(tableId, gameId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized void leaveAwaitingTables(String playerId) {
|
||||
Map<String, AwaitingTable> copy = new HashMap<String, AwaitingTable>(_awaitingTables);
|
||||
for (Map.Entry<String, AwaitingTable> table : copy.entrySet()) {
|
||||
if (table.getValue().hasPlayer(playerId)) {
|
||||
boolean empty = table.getValue().removePlayer(playerId);
|
||||
if (empty)
|
||||
_awaitingTables.remove(table.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getPlayerTable(String playerId) {
|
||||
for (Map.Entry<String, AwaitingTable> table : _awaitingTables.entrySet()) {
|
||||
if (table.getValue().hasPlayer(playerId))
|
||||
return table.getKey();
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> runningTable : _runningTables.entrySet()) {
|
||||
String gameId = runningTable.getValue();
|
||||
LotroGameMediator lotroGameMediator = _lotroServer.getGameById(gameId);
|
||||
if (lotroGameMediator != null)
|
||||
if (lotroGameMediator.getPlayersPlaying().contains(playerId))
|
||||
return runningTable.getKey();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isPlayerBusy(String playerId) {
|
||||
for (AwaitingTable awaitingTable : _awaitingTables.values())
|
||||
if (awaitingTable.hasPlayer(playerId))
|
||||
return true;
|
||||
|
||||
for (String gameId : _runningTables.values()) {
|
||||
LotroGameMediator lotroGameMediator = _lotroServer.getGameById(gameId);
|
||||
if (lotroGameMediator.getPlayersPlaying().contains(playerId))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanup() {
|
||||
// Remove finished games
|
||||
HashMap<String, String> copy = new HashMap<String, String>(_runningTables);
|
||||
for (Map.Entry<String, String> runningTable : copy.entrySet()) {
|
||||
if (_lotroServer.getGameById(runningTable.getValue()) == null)
|
||||
_runningTables.remove(runningTable.getKey());
|
||||
}
|
||||
|
||||
long currentTime = System.currentTimeMillis();
|
||||
Map<String, Long> visitCopy = new LinkedHashMap<String, Long>(_lastVisitedPlayers);
|
||||
for (Map.Entry<String, Long> lastVisitedPlayer : visitCopy.entrySet()) {
|
||||
if (currentTime > lastVisitedPlayer.getValue() + _playerInactivityPeriod) {
|
||||
String playerId = lastVisitedPlayer.getKey();
|
||||
_lastVisitedPlayers.remove(playerId);
|
||||
leaveAwaitingTables(playerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
package com.gempukku.lotro.server;
|
||||
|
||||
import com.gempukku.lotro.GameEvent;
|
||||
import com.gempukku.lotro.LotroGameMediator;
|
||||
import com.gempukku.lotro.LotroGameParticipant;
|
||||
import com.gempukku.lotro.LotroServer;
|
||||
import com.gempukku.lotro.chat.ChatMessage;
|
||||
import com.gempukku.lotro.chat.ChatRoomMediator;
|
||||
import com.gempukku.lotro.chat.ChatServer;
|
||||
@@ -11,9 +7,8 @@ import com.gempukku.lotro.db.DeckDAO;
|
||||
import com.gempukku.lotro.db.PlayerDAO;
|
||||
import com.gempukku.lotro.db.vo.Deck;
|
||||
import com.gempukku.lotro.db.vo.Player;
|
||||
import com.gempukku.lotro.game.CardCollection;
|
||||
import com.gempukku.lotro.game.DefaultLotroFormat;
|
||||
import com.gempukku.lotro.game.ParticipantCommunicationVisitor;
|
||||
import com.gempukku.lotro.game.*;
|
||||
import com.gempukku.lotro.hall.HallServer;
|
||||
import com.gempukku.lotro.logic.decisions.AwaitingDecision;
|
||||
import com.sun.jersey.spi.resource.Singleton;
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
@@ -38,6 +33,7 @@ import java.util.Map;
|
||||
public class ServerResource {
|
||||
private static final Logger _logger = Logger.getLogger(ServerResource.class);
|
||||
|
||||
private HallServer _hallServer;
|
||||
private LotroServer _lotroServer;
|
||||
private ChatServer _chatServer;
|
||||
|
||||
@@ -47,10 +43,12 @@ public class ServerResource {
|
||||
try {
|
||||
_chatServer = new ChatServer();
|
||||
_chatServer.startServer();
|
||||
_chatServer.createChatRoom("default");
|
||||
|
||||
_lotroServer = new LotroServer(_chatServer);
|
||||
_lotroServer.startServer();
|
||||
|
||||
_hallServer = new HallServer(_lotroServer, _chatServer);
|
||||
_hallServer.startServer();
|
||||
} catch (RuntimeException exp) {
|
||||
_logger.error("Error while creating resource", exp);
|
||||
exp.printStackTrace();
|
||||
|
||||
Reference in New Issue
Block a user