mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
Added data collectors, AI and testing tools improves:
- dev: added data collectors API to collect and process game data in real time; - tests: added game logs output in all unit tests (enabled by default); - tests: added games history storage (decks, game logs, chats - disabled by default);
This commit is contained in:
parent
9812e133e1
commit
52180d1393
30 changed files with 1007 additions and 80 deletions
|
|
@ -192,11 +192,6 @@
|
|||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import mage.cards.repository.CardInfo;
|
|||
import mage.cards.repository.CardRepository;
|
||||
import mage.constants.Constants;
|
||||
import mage.game.Game;
|
||||
import mage.game.Table;
|
||||
import mage.game.tournament.Tournament;
|
||||
import mage.server.game.GameController;
|
||||
import mage.server.managers.ChatManager;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
|
|
@ -40,11 +42,39 @@ public class ChatManagerImpl implements ChatManager {
|
|||
this.managerFactory = managerFactory;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UUID createChatSession(String info) {
|
||||
public UUID createRoomChatSession(UUID roomId) {
|
||||
return createChatSession("Room " + roomId)
|
||||
.withRoom(roomId)
|
||||
.getChatId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID createTourneyChatSession(Tournament tournament) {
|
||||
return createChatSession("Tourney " + tournament.getId())
|
||||
.withTourney(tournament)
|
||||
.getChatId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID createTableChatSession(Table table) {
|
||||
return createChatSession("Table " + table.getId())
|
||||
.withTable(table)
|
||||
.getChatId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID createGameChatSession(Game game) {
|
||||
return createChatSession("Game " + game.getId())
|
||||
.withGame(game)
|
||||
.getChatId();
|
||||
}
|
||||
|
||||
private ChatSession createChatSession(String info) {
|
||||
ChatSession chatSession = new ChatSession(managerFactory, info);
|
||||
chatSessions.put(chatSession.getChatId(), chatSession);
|
||||
return chatSession.getChatId();
|
||||
return chatSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -94,7 +124,7 @@ public class ChatManagerImpl implements ChatManager {
|
|||
ChatSession chatSession = chatSessions.get(chatId);
|
||||
Optional<User> user = managerFactory.userManager().getUserByName(userName);
|
||||
if (chatSession != null) {
|
||||
// special commads
|
||||
// special commands
|
||||
if (message.startsWith("\\") || message.startsWith("/")) {
|
||||
if (user.isPresent()) {
|
||||
if (!performUserCommand(user.get(), message, chatId, false)) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package mage.server;
|
||||
|
||||
import mage.collectors.DataCollectorServices;
|
||||
import mage.game.Game;
|
||||
import mage.game.Table;
|
||||
import mage.game.tournament.Tournament;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.interfaces.callback.ClientCallbackMethod;
|
||||
import mage.server.managers.ManagerFactory;
|
||||
|
|
@ -27,6 +30,13 @@ public class ChatSession {
|
|||
private final ManagerFactory managerFactory;
|
||||
private final ReadWriteLock lock = new ReentrantReadWriteLock(); // TODO: no needs due ConcurrentHashMap usage?
|
||||
|
||||
// only 1 field must be filled per chat type
|
||||
// TODO: rework chat sessions to share logic (one server room/lobby + one table/subtable + one games/match)
|
||||
private UUID roomId = null;
|
||||
private UUID tourneyId = null;
|
||||
private UUID tableId = null;
|
||||
private UUID gameId = null;
|
||||
|
||||
private final ConcurrentMap<UUID, String> users = new ConcurrentHashMap<>(); // active users
|
||||
private final Set<UUID> usersHistory = new HashSet<>(); // all users that was here (need for system messages like connection problem)
|
||||
private final UUID chatId;
|
||||
|
|
@ -40,6 +50,26 @@ public class ChatSession {
|
|||
this.info = info;
|
||||
}
|
||||
|
||||
public ChatSession withRoom(UUID roomId) {
|
||||
this.roomId = roomId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatSession withTourney(Tournament tournament) {
|
||||
this.tourneyId = tournament.getId();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatSession withTable(Table table) {
|
||||
this.tableId = table.getId();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatSession withGame(Game game) {
|
||||
this.gameId = game.getId();
|
||||
return this;
|
||||
}
|
||||
|
||||
public void join(UUID userId) {
|
||||
managerFactory.userManager().getUser(userId).ifPresent(user -> {
|
||||
if (!users.containsKey(userId)) {
|
||||
|
|
@ -112,9 +142,36 @@ public class ChatSession {
|
|||
// TODO: is it freeze on someone's connection fail/freeze with play multiple games/chats/lobby?
|
||||
// TODO: send messages in another thread?!
|
||||
if (!message.isEmpty()) {
|
||||
ChatMessage chatMessage = new ChatMessage(userName, message, (withTime ? new Date() : null), game, color, messageType, soundToPlay);
|
||||
|
||||
switch (messageType) {
|
||||
case USER_INFO:
|
||||
case STATUS:
|
||||
case TALK:
|
||||
if (this.roomId != null) {
|
||||
DataCollectorServices.getInstance().onChatRoom(this.roomId, userName, message);
|
||||
} else if (this.tourneyId != null) {
|
||||
DataCollectorServices.getInstance().onChatTourney(this.tourneyId, userName, message);
|
||||
} else if (this.tableId != null) {
|
||||
DataCollectorServices.getInstance().onChatTable(this.tableId, userName, message);
|
||||
} else if (this.gameId != null) {
|
||||
DataCollectorServices.getInstance().onChatGame(this.gameId, userName, message);
|
||||
}
|
||||
break;
|
||||
case GAME:
|
||||
// game logs processing in other place
|
||||
break;
|
||||
case WHISPER_FROM:
|
||||
case WHISPER_TO:
|
||||
// ignore private messages
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unsupported message type " + messageType);
|
||||
}
|
||||
|
||||
// TODO: wtf, remove all that locks/tries and make it simpler
|
||||
Set<UUID> clientsToRemove = new HashSet<>();
|
||||
ClientCallback clientCallback = new ClientCallback(ClientCallbackMethod.CHATMESSAGE, chatId,
|
||||
new ChatMessage(userName, message, (withTime ? new Date() : null), game, color, messageType, soundToPlay));
|
||||
ClientCallback clientCallback = new ClientCallback(ClientCallbackMethod.CHATMESSAGE, chatId, chatMessage);
|
||||
List<UUID> chatUserIds = new ArrayList<>();
|
||||
final Lock r = lock.readLock();
|
||||
r.lock();
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import mage.cards.decks.DeckCardLists;
|
|||
import mage.cards.decks.DeckValidatorFactory;
|
||||
import mage.cards.repository.CardRepository;
|
||||
import mage.cards.repository.ExpansionRepository;
|
||||
import mage.collectors.DataCollectorServices;
|
||||
import mage.constants.Constants;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.PlayerAction;
|
||||
|
|
@ -29,6 +30,7 @@ import mage.server.managers.ManagerFactory;
|
|||
import mage.server.services.impl.FeedbackServiceImpl;
|
||||
import mage.server.tournament.TournamentFactory;
|
||||
import mage.server.util.ServerMessagesUtil;
|
||||
import mage.util.DebugUtil;
|
||||
import mage.utils.*;
|
||||
import mage.view.*;
|
||||
import mage.view.ChatMessage.MessageColor;
|
||||
|
|
@ -68,6 +70,13 @@ public class MageServerImpl implements MageServer {
|
|||
this.detailsMode = detailsMode;
|
||||
this.callExecutor = managerFactory.threadExecutor().getCallExecutor();
|
||||
ServerMessagesUtil.instance.getMessages();
|
||||
|
||||
// additional logs
|
||||
DataCollectorServices.init(
|
||||
DebugUtil.SERVER_DATA_COLLECTORS_ENABLE_PRINT_GAME_LOGS,
|
||||
DebugUtil.SERVER_DATA_COLLECTORS_ENABLE_SAVE_GAME_HISTORY
|
||||
);
|
||||
DataCollectorServices.getInstance().onServerStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ public abstract class RoomImpl implements Room {
|
|||
|
||||
public RoomImpl(ChatManager chatManager) {
|
||||
roomId = UUID.randomUUID();
|
||||
chatId = chatManager.createChatSession("Room " + roomId);
|
||||
chatId = chatManager.createRoomChatSession(roomId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ public class TableController {
|
|||
}
|
||||
this.table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.instance.createDeckValidator(options.getDeckType()),
|
||||
options.getPlayerTypes(), new TableRecorderImpl(managerFactory.userManager()), match, options.getBannedUsers(), options.isPlaneChase());
|
||||
this.chatId = managerFactory.chatManager().createChatSession("Match Table " + table.getId());
|
||||
this.chatId = managerFactory.chatManager().createTableChatSession(table);
|
||||
init();
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +94,7 @@ public class TableController {
|
|||
}
|
||||
table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.instance.createDeckValidator(options.getMatchOptions().getDeckType()),
|
||||
options.getPlayerTypes(), new TableRecorderImpl(managerFactory.userManager()), tournament, options.getMatchOptions().getBannedUsers(), options.isPlaneChase());
|
||||
chatId = managerFactory.chatManager().createChatSession("Tourney table " + table.getId());
|
||||
chatId = managerFactory.chatManager().createTableChatSession(table);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
|
|
|
|||
|
|
@ -85,11 +85,11 @@ public class GameController implements GameCallback {
|
|||
|
||||
public GameController(ManagerFactory managerFactory, Game game, ConcurrentMap<UUID, UUID> userPlayerMap, UUID tableId, UUID choosingPlayerId, GameOptions gameOptions) {
|
||||
this.managerFactory = managerFactory;
|
||||
gameExecutor = managerFactory.threadExecutor().getGameExecutor();
|
||||
responseIdleTimeoutExecutor = managerFactory.threadExecutor().getTimeoutIdleExecutor();
|
||||
gameSessionId = UUID.randomUUID();
|
||||
this.gameExecutor = managerFactory.threadExecutor().getGameExecutor();
|
||||
this.responseIdleTimeoutExecutor = managerFactory.threadExecutor().getTimeoutIdleExecutor();
|
||||
this.gameSessionId = UUID.randomUUID();
|
||||
this.userPlayerMap = userPlayerMap;
|
||||
chatId = managerFactory.chatManager().createChatSession("Game " + game.getId());
|
||||
this.chatId = managerFactory.chatManager().createGameChatSession(game);
|
||||
this.userRequestingRollback = null;
|
||||
this.game = game;
|
||||
this.game.setSaveGame(managerFactory.configSettings().isSaveGameActivated());
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package mage.server.managers;
|
||||
|
||||
import mage.game.Game;
|
||||
import mage.game.Table;
|
||||
import mage.game.tournament.Tournament;
|
||||
import mage.server.ChatSession;
|
||||
import mage.server.DisconnectReason;
|
||||
import mage.view.ChatMessage;
|
||||
|
|
@ -10,7 +12,13 @@ import java.util.UUID;
|
|||
|
||||
public interface ChatManager {
|
||||
|
||||
UUID createChatSession(String info);
|
||||
UUID createRoomChatSession(UUID roomId);
|
||||
|
||||
UUID createTourneyChatSession(Tournament tournament);
|
||||
|
||||
UUID createTableChatSession(Table table);
|
||||
|
||||
UUID createGameChatSession(Game game);
|
||||
|
||||
void joinChat(UUID chatId, UUID userId);
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public class TournamentController {
|
|||
public TournamentController(ManagerFactory managerFactory, Tournament tournament, ConcurrentMap<UUID, UUID> userPlayerMap, UUID tableId) {
|
||||
this.managerFactory = managerFactory;
|
||||
this.userPlayerMap = userPlayerMap;
|
||||
chatId = managerFactory.chatManager().createChatSession("Tournament " + tournament.getId());
|
||||
this.chatId = managerFactory.chatManager().createTourneyChatSession(tournament);
|
||||
this.tournament = tournament;
|
||||
this.tableId = tableId;
|
||||
init();
|
||||
|
|
@ -261,9 +261,7 @@ public class TournamentController {
|
|||
table.setState(TableState.STARTING);
|
||||
tableManager.startTournamentSubMatch(null, table.getId());
|
||||
tableManager.getMatch(table.getId()).ifPresent(match -> {
|
||||
match.setTableId(tableId);
|
||||
pair.setMatch(match);
|
||||
pair.setTableId(table.getId());
|
||||
pair.setMatchAndTable(match, table.getId());
|
||||
player1.setState(TournamentPlayerState.DUELING);
|
||||
player2.setState(TournamentPlayerState.DUELING);
|
||||
});
|
||||
|
|
@ -291,9 +289,7 @@ public class TournamentController {
|
|||
table.setState(TableState.STARTING);
|
||||
tableManager.startTournamentSubMatch(null, table.getId());
|
||||
tableManager.getMatch(table.getId()).ifPresent(match -> {
|
||||
match.setTableId(tableId);
|
||||
round.setMatch(match);
|
||||
round.setTableId(table.getId());
|
||||
round.setMatchAndTable(match, table.getId());
|
||||
for (TournamentPlayer player : round.getAllPlayers()) {
|
||||
player.setState(TournamentPlayerState.DUELING);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue