Moved the creation of games and broadcasting outside of tournament lock to prevent theoretical deadlocks. These actions are now made through a list of actions returned from tournament advance method.

This commit is contained in:
MarcinSc
2024-08-28 12:16:58 +07:00
parent ea31ff2bae
commit cc4677aca6
3 changed files with 42 additions and 64 deletions

View File

@@ -23,7 +23,6 @@ import com.gempukku.lotro.logic.vo.LotroDeck;
import com.gempukku.lotro.packs.ProductLibrary; import com.gempukku.lotro.packs.ProductLibrary;
import com.gempukku.lotro.service.AdminService; import com.gempukku.lotro.service.AdminService;
import com.gempukku.lotro.tournament.TournamentService; import com.gempukku.lotro.tournament.TournamentService;
import com.gempukku.util.JsonUtils;
import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
@@ -401,8 +400,7 @@ public class AdminRequestHandler extends LotroServerRequestHandler implements Ur
decks.put(player.getName(), deck); decks.put(player.getName(), deck);
} }
var spawner = _hallServer.createManualGameSpawner(tournament.getTournamentName(), format, timer, name);
var spawner = _hallServer.GetManualGameSpawner(tournament, format, timer, name);
for(int i = 0; i < playerones.size(); i++) { for(int i = 0; i < playerones.size(); i++) {
String p1 = playerones.get(i); String p1 = playerones.get(i);
String p2 = playertwos.get(i); String p2 = playertwos.get(i);

View File

@@ -120,7 +120,6 @@ public class ServerBuilder {
extract(objectMap, TournamentService.class), extract(objectMap, TournamentService.class),
extract(objectMap, LotroCardBlueprintLibrary.class), extract(objectMap, LotroCardBlueprintLibrary.class),
extract(objectMap, LotroFormatLibrary.class), extract(objectMap, LotroFormatLibrary.class),
extract(objectMap, ProductLibrary.class),
extract(objectMap, CollectionsManager.class), extract(objectMap, CollectionsManager.class),
extract(objectMap, AdminService.class) extract(objectMap, AdminService.class)
)); ));

View File

@@ -22,6 +22,7 @@ import com.gempukku.lotro.service.AdminService;
import com.gempukku.lotro.tournament.*; import com.gempukku.lotro.tournament.*;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
@@ -30,9 +31,7 @@ import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
public class HallServer extends AbstractServer { public class HallServer extends AbstractServer {
private static final int _playerTableInactivityPeriod = 1000 * 20; // 20 seconds
private static final int _playerTableInactivityPeriod = 1000 * 20 ; // 20 seconds
private static final int _playerChatInactivityPeriod = 1000 * 60 * 5; // 5 minutes private static final int _playerChatInactivityPeriod = 1000 * 60 * 5; // 5 minutes
@@ -41,13 +40,11 @@ public class HallServer extends AbstractServer {
private final TournamentService _tournamentService; private final TournamentService _tournamentService;
private final LotroCardBlueprintLibrary _library; private final LotroCardBlueprintLibrary _library;
private final LotroFormatLibrary _formatLibrary; private final LotroFormatLibrary _formatLibrary;
private final ProductLibrary _productLibrary;
private final CollectionsManager _collectionsManager; private final CollectionsManager _collectionsManager;
private final LotroServer _lotroServer; private final LotroServer _lotroServer;
private final AdminService _adminService; private final AdminService _adminService;
private final CollectionType _defaultCollectionType = CollectionType.ALL_CARDS; private final CollectionType _defaultCollectionType = CollectionType.ALL_CARDS;
private final CollectionType _tournamentCollectionType = CollectionType.OWNED_TOURNAMENT_CARDS;
private String _motd; private String _motd;
@@ -60,24 +57,19 @@ public class HallServer extends AbstractServer {
private final Map<Player, HallCommunicationChannel> _playerChannelCommunication = new ConcurrentHashMap<>(); private final Map<Player, HallCommunicationChannel> _playerChannelCommunication = new ConcurrentHashMap<>();
private int _nextChannelNumber = 0; private int _nextChannelNumber = 0;
private final ChatRoomMediator _hallChat; private final ChatRoomMediator _hallChat;
private final GameResultListener _notifyHallListeners = new NotifyHallListenersGameResultListener(); private final GameResultListener _notifyHallListeners = new NotifyHallListenersGameResultListener();
private static final Logger _log = LogManager.getLogger(HallServer.class); private static final Logger _log = LogManager.getLogger(HallServer.class);
public HallServer(IgnoreDAO ignoreDAO, LotroServer lotroServer, ChatServer chatServer, LeagueService leagueService, TournamentService tournamentService, LotroCardBlueprintLibrary library, public HallServer(IgnoreDAO ignoreDAO, LotroServer lotroServer, ChatServer chatServer, LeagueService leagueService, TournamentService tournamentService, LotroCardBlueprintLibrary library,
LotroFormatLibrary formatLibrary, ProductLibrary productLibrary, CollectionsManager collectionsManager, AdminService adminService) { LotroFormatLibrary formatLibrary, CollectionsManager collectionsManager, AdminService adminService) {
_lotroServer = lotroServer; _lotroServer = lotroServer;
_chatServer = chatServer; _chatServer = chatServer;
_leagueService = leagueService; _leagueService = leagueService;
_tournamentService = tournamentService; _tournamentService = tournamentService;
_library = library; _library = library;
_formatLibrary = formatLibrary; _formatLibrary = formatLibrary;
_productLibrary = productLibrary;
_collectionsManager = collectionsManager; _collectionsManager = collectionsManager;
_adminService = adminService; _adminService = adminService;
@@ -201,20 +193,20 @@ public class HallServer extends AbstractServer {
public void commandReceived(String from, String parameters, boolean admin) { public void commandReceived(String from, String parameters, boolean admin) {
//_hallChat.sendToUser("System", from, //_hallChat.sendToUser("System", from,
String message = """ String message = """
List of available commands: List of available commands:
/ignore username - Adds user 'username' to list of your ignores /ignore username - Adds user 'username' to list of your ignores
/unignore username - Removes user 'username' from list of your ignores /unignore username - Removes user 'username' from list of your ignores
/listIgnores - Lists all your ignored users /listIgnores - Lists all your ignored users
/incognito - Makes you incognito (not visible in user list) /incognito - Makes you incognito (not visible in user list)
/endIncognito - Turns your visibility 'on' again"""; /endIncognito - Turns your visibility 'on' again""";
if (admin) { if (admin) {
message += """ message += """
Admin only commands: Admin only commands:
/ban username - Bans user 'username' permanently /ban username - Bans user 'username' permanently
/banIp ip - Bans specified ip permanently /banIp ip - Bans specified ip permanently
/banIpRange ip - Bans ips with the specified prefix, ie. 10.10.10."""; /banIpRange ip - Bans ips with the specified prefix, ie. 10.10.10.""";
} }
_hallChat.sendToUser("System", from, message.replace("\n", "<br />")); _hallChat.sendToUser("System", from, message.replace("\n", "<br />"));
@@ -227,8 +219,6 @@ public class HallServer extends AbstractServer {
_hallChat.sendToUser("System", from, "\"" + parameters + "\" is not a recognized command."); _hallChat.sendToUser("System", from, "\"" + parameters + "\" is not a recognized command.");
} }
}); });
} }
private void hallChanged() { private void hallChanged() {
@@ -241,8 +231,7 @@ public class HallServer extends AbstractServer {
_hallDataAccessLock.writeLock().lock(); _hallDataAccessLock.writeLock().lock();
try { try {
_tournamentService.reloadTournaments(); _tournamentService.reloadTournaments();
} } finally {
finally {
_hallDataAccessLock.writeLock().unlock(); _hallDataAccessLock.writeLock().unlock();
} }
} }
@@ -257,8 +246,7 @@ public class HallServer extends AbstractServer {
_tournamentService.cancelAllTournamentQueues(); _tournamentService.cancelAllTournamentQueues();
_chatServer.sendSystemMessageToAllChatRooms("@everyone System is entering shutdown mode and will be restarted when all games are finished."); _chatServer.sendSystemMessageToAllChatRooms("@everyone System is entering shutdown mode and will be restarted when all games are finished.");
hallChanged(); hallChanged();
} } else if (cancelMessage) {
else if(cancelMessage){
_chatServer.sendSystemMessageToAllChatRooms("@everyone Shutdown mode canceled; games may now resume."); _chatServer.sendSystemMessageToAllChatRooms("@everyone Shutdown mode canceled; games may now resume.");
} }
} finally { } finally {
@@ -298,8 +286,6 @@ public class HallServer extends AbstractServer {
tableHolder.cancelWaitingTables(); tableHolder.cancelWaitingTables();
} }
/** /**
* @return If table created, otherwise <code>false</code> (if the user already is sitting at a table or playing). * @return If table created, otherwise <code>false</code> (if the user already is sitting at a table or playing).
*/ */
@@ -358,16 +344,16 @@ public class HallServer extends AbstractServer {
if (leagueSerie == null) if (leagueSerie == null)
throw new HallException("There is no ongoing serie for that league"); throw new HallException("There is no ongoing serie for that league");
if(isInviteOnly) { if (isInviteOnly) {
throw new HallException("League games cannot be invite-only"); throw new HallException("League games cannot be invite-only");
} }
if(isPrivate) { if (isPrivate) {
throw new HallException("League games cannot be private"); throw new HallException("League games cannot be private");
} }
//Don't want people getting around the anonymity for leagues. //Don't want people getting around the anonymity for leagues.
if(description != null) if (description != null)
description = ""; description = "";
format = leagueSerie.getFormat(); format = leagueSerie.getFormat();
@@ -405,8 +391,7 @@ public class HallServer extends AbstractServer {
hallChanged(); hallChanged();
return true; return true;
} } finally {
finally {
_hallDataAccessLock.writeLock().unlock(); _hallDataAccessLock.writeLock().unlock();
} }
} }
@@ -584,8 +569,7 @@ public class HallServer extends AbstractServer {
private LotroDeck validateUserAndDeck(LotroFormat format, Player player, CollectionType collectionType, LotroDeck lotroDeck) throws HallException, DeckInvalidException { private LotroDeck validateUserAndDeck(LotroFormat format, Player player, CollectionType collectionType, LotroDeck lotroDeck) throws HallException, DeckInvalidException {
String validation = format.validateDeckForHall(lotroDeck); String validation = format.validateDeckForHall(lotroDeck);
if(validation == null || !validation.isEmpty()) if (validation == null || !validation.isEmpty()) {
{
throw new DeckInvalidException(validation); throw new DeckInvalidException(validation);
} }
@@ -599,7 +583,7 @@ public class HallServer extends AbstractServer {
filteredSpecialCardsDeck.setRing(filterCard(lotroDeck.getRing(), ownedCollection)); filteredSpecialCardsDeck.setRing(filterCard(lotroDeck.getRing(), ownedCollection));
filteredSpecialCardsDeck.setRingBearer(filterCard(lotroDeck.getRingBearer(), ownedCollection)); filteredSpecialCardsDeck.setRingBearer(filterCard(lotroDeck.getRingBearer(), ownedCollection));
if(format.usesMaps() && lotroDeck.getMap() != null) { if (format.usesMaps() && lotroDeck.getMap() != null) {
filteredSpecialCardsDeck.setMap(filterCard(lotroDeck.getMap(), ownedCollection)); filteredSpecialCardsDeck.setMap(filterCard(lotroDeck.getMap(), ownedCollection));
} }
@@ -613,9 +597,9 @@ public class HallServer extends AbstractServer {
int owned = ownedCollection.getItemCount(blueprintId); int owned = ownedCollection.getItemCount(blueprintId);
//Since the cards we are validating may be automatic errata IDs, we check and see //Since the cards we are validating may be automatic errata IDs, we check and see
// if the base version of the errata ID is owned in foil, and count that if so. // if the base version of the errata ID is owned in foil, and count that if so.
if(blueprintId.endsWith("*")) { if (blueprintId.endsWith("*")) {
var ids = format.findBaseCards(_library.getBaseBlueprintId(blueprintId)); var ids = format.findBaseCards(_library.getBaseBlueprintId(blueprintId));
if(ids.size() == 1) { if (ids.size() == 1) {
owned += ownedCollection.getItemCount(ids.stream().findFirst() + "*"); owned += ownedCollection.getItemCount(ids.stream().findFirst() + "*");
} }
} }
@@ -629,10 +613,9 @@ public class HallServer extends AbstractServer {
String baseBlueprintId = _library.getBaseBlueprintId(blueprintId); String baseBlueprintId = _library.getBaseBlueprintId(blueprintId);
for (int i = 0; i < (count - fromOwned); i++) { for (int i = 0; i < (count - fromOwned); i++) {
//hacking in foil support for errata foils //hacking in foil support for errata foils
if(set > 19 && blueprintId.endsWith("*")) { if (set > 19 && blueprintId.endsWith("*")) {
filteredSpecialCardsDeck.addCard(blueprintId); filteredSpecialCardsDeck.addCard(blueprintId);
} } else {
else {
filteredSpecialCardsDeck.addCard(baseBlueprintId); filteredSpecialCardsDeck.addCard(baseBlueprintId);
} }
} }
@@ -654,12 +637,12 @@ public class HallServer extends AbstractServer {
int collectionCount = collection.getItemCount(cardCount.getKey()); int collectionCount = collection.getItemCount(cardCount.getKey());
if(!errataID.equals(overtID)) { if (!errataID.equals(overtID)) {
collection.getItemCount(errataID); collection.getItemCount(errataID);
} }
var alts = _library.getAllAlternates(cardCount.getKey()); var alts = _library.getAllAlternates(cardCount.getKey());
if(alts != null) { if (alts != null) {
for (String id : alts) { for (String id : alts) {
collectionCount += collection.getItemCount(id); collectionCount += collection.getItemCount(id);
} }
@@ -770,7 +753,7 @@ public class HallServer extends AbstractServer {
} }
} }
if(forceRefresh) { if (forceRefresh) {
_tournamentService.reloadTournaments(); _tournamentService.reloadTournaments();
} }
@@ -783,15 +766,13 @@ public class HallServer extends AbstractServer {
} }
_tickCounter++; _tickCounter++;
if(changed) { if (changed) {
hallChanged(); hallChanged();
} }
} } catch (Exception ex) {
catch (Exception ex) {
throw new RuntimeException("Error during server cleanup.", ex); throw new RuntimeException("Error during server cleanup.", ex);
} } finally {
finally {
_hallDataAccessLock.writeLock().unlock(); _hallDataAccessLock.writeLock().unlock();
} }
} }
@@ -812,7 +793,7 @@ public class HallServer extends AbstractServer {
tournamentGameSettings = new GameSettings(null, _formatLibrary.getFormat(_tournament.getFormat()), tournamentGameSettings = new GameSettings(null, _formatLibrary.getFormat(_tournament.getFormat()),
null, null, true, true, false, false, GameTimer.TOURNAMENT_TIMER, null); null, null, true, true, false, false, GameTimer.TOURNAMENT_TIMER, null);
wcGameSettings = new GameSettings(null, _formatLibrary.getFormat(_tournament.getFormat()), wcGameSettings = new GameSettings(null, _formatLibrary.getFormat(_tournament.getFormat()),
null, null, true, true, false, false, GameTimer.CHAMPIONSHIP_TIMER, null); null, null, true, true, false, false, GameTimer.CHAMPIONSHIP_TIMER, null);
} }
@@ -829,7 +810,7 @@ public class HallServer extends AbstractServer {
try { try {
if (!_shutdown) { if (!_shutdown) {
var settings = tournamentGameSettings; var settings = tournamentGameSettings;
if(_tournament.getTournamentId().toLowerCase().contains("wc")) { if (_tournament.getTournamentId().toLowerCase().contains("wc")) {
settings = wcGameSettings; settings = wcGameSettings;
} }
final GameTable gameTable = tableHolder.setupTournamentTable(settings, participants); final GameTable gameTable = tableHolder.setupTournamentTable(settings, participants);
@@ -865,16 +846,16 @@ public class HallServer extends AbstractServer {
} }
} }
public ManualGameSpawner GetManualGameSpawner(Tournament tournament, LotroFormat format, GameTimer timer, String description) { public ManualGameSpawner createManualGameSpawner(String tournamentName, LotroFormat format, GameTimer timer, String description) {
return new ManualGameSpawner(tournament, format, timer, description); return new ManualGameSpawner(tournamentName, format, timer, description);
} }
public class ManualGameSpawner implements TournamentCallback { public class ManualGameSpawner implements TournamentCallback {
private final Tournament _tournament; private final String _tournamentName;
private final GameSettings _settings; private final GameSettings _settings;
private ManualGameSpawner(Tournament tournament, LotroFormat format, GameTimer timer, String description) { private ManualGameSpawner(String tournamentName, LotroFormat format, GameTimer timer, String description) {
_tournament = tournament; _tournamentName = tournamentName;
_settings = new GameSettings(null, format, _settings = new GameSettings(null, format,
null, null, true, false, false, false, timer, description); null, null, true, false, false, false, timer, description);
} }
@@ -893,7 +874,7 @@ public class HallServer extends AbstractServer {
if (!_shutdown) { if (!_shutdown) {
final GameTable gameTable = tableHolder.setupTournamentTable(_settings, participants); final GameTable gameTable = tableHolder.setupTournamentTable(_settings, participants);
final LotroGameMediator mediator = createGameMediator(participants, final LotroGameMediator mediator = createGameMediator(participants,
_notifyHallListeners, _tournament.getTournamentName(), _settings); _notifyHallListeners, _tournamentName, _settings);
gameTable.startGame(mediator); gameTable.startGame(mediator);
} }
} finally { } finally {