Füge Unterstützung für Würfelspiele hinzu und verbessere Debugging-Optionen
- Implementiere neue Funktionen in der ChatRoom-Klasse für das Starten, Rollen und Beenden von Würfelspielen. - Füge eine Option zur Aktivierung von Debug-Logging in CMake hinzu, um die Entwicklung zu erleichtern. - Aktualisiere die ChatUser-Klasse, um die Interaktion mit dem Würfelspiel zu ermöglichen. - Verbessere die Socket-Verwaltung im Server, um WebSocket-Verbindungen zu unterstützen und die Handhabung von Anfragen zu optimieren. - Aktualisiere die Konfiguration, um die neue Funktionalität zu unterstützen und die Benutzererfahrung zu verbessern.
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Yc
|
||||
{
|
||||
@@ -19,7 +20,10 @@ namespace Yc
|
||||
_parent(std::move(parent)),
|
||||
_blocked(false),
|
||||
_stop(false),
|
||||
_roundRunning(false)
|
||||
_roundRunning(false),
|
||||
_diceGameRunning(false),
|
||||
_currentRound(0),
|
||||
_totalRounds(0)
|
||||
{
|
||||
_name = roomParams["name"].asString();
|
||||
_password = roomParams["password"].asString();
|
||||
@@ -37,6 +41,12 @@ namespace Yc
|
||||
|
||||
void ChatRoom::run()
|
||||
{
|
||||
// Nachrichtentypen, die nicht an den Auslöser zurückgeschickt werden
|
||||
static const std::unordered_set<std::string> kSuppressToSender = {
|
||||
"room_entered",
|
||||
"user_entered_room",
|
||||
"user_color_changed"
|
||||
};
|
||||
while (!_stop)
|
||||
{
|
||||
if (_msgQueue.size() > 0 && !_blocked)
|
||||
@@ -47,6 +57,18 @@ namespace Yc
|
||||
Message message = _msgQueue.front();
|
||||
for (auto &user : _users)
|
||||
{
|
||||
// Konfigurierbare Unterdrückung für Systemmeldungen an den Sender
|
||||
if (message.type == ChatUser::system) {
|
||||
bool suppress = false;
|
||||
// message.messageTr kann JSON (mit tr) oder plain String sein
|
||||
Json::Value maybeJson = getJsonTree(message.messageTr);
|
||||
if (maybeJson.isObject() && maybeJson.isMember("tr")) {
|
||||
suppress = kSuppressToSender.count(maybeJson["tr"].asString()) > 0;
|
||||
} else {
|
||||
suppress = kSuppressToSender.count(message.messageTr) > 0;
|
||||
}
|
||||
if (suppress && user->name() == message.userName) continue;
|
||||
}
|
||||
user->sendMsg(message.type, message.messageTr, message.userName, message.color);
|
||||
}
|
||||
_msgQueue.pop();
|
||||
@@ -69,8 +91,29 @@ namespace Yc
|
||||
}
|
||||
auto newUser = std::make_shared<ChatUser>(shared_from_this(), _userName, color, socket);
|
||||
_users.push_back(newUser);
|
||||
newUser->sendMsg(ChatUser::roomList, _parent->jsonRoomList(), "", "");
|
||||
addMessage(ChatUser::system, "room_entered", newUser->name(), newUser->color());
|
||||
newUser->start();
|
||||
Json::Value roomList = _parent->jsonRoomList();
|
||||
newUser->sendMsg(ChatUser::roomList, roomList, "", "");
|
||||
// Private Rückmeldung an den User: In welchem Raum befindet er/sie sich jetzt?
|
||||
{
|
||||
Json::Value msg = Json::objectValue;
|
||||
msg["tr"] = "room_entered";
|
||||
msg["to"] = _name;
|
||||
newUser->sendMsg(ChatUser::system, msg, "", "");
|
||||
}
|
||||
// Sende aktuelle Userliste an den neuen User
|
||||
Json::Value currentUserList = userList();
|
||||
newUser->sendMsg(ChatUser::userListe, currentUserList, "", "");
|
||||
|
||||
// Sende aktualisierte Userliste an alle anderen User im Raum
|
||||
for (auto &existingUser : _users) {
|
||||
if (existingUser != newUser) {
|
||||
existingUser->sendMsg(ChatUser::userListe, currentUserList, "", "");
|
||||
}
|
||||
}
|
||||
|
||||
// Broadcast an andere Nutzer: Benutzer X hat den Raum betreten (mit Farbinfo)
|
||||
addMessage(ChatUser::system, "user_entered_room", newUser->name(), newUser->color());
|
||||
_initRound();
|
||||
return true;
|
||||
}
|
||||
@@ -107,7 +150,7 @@ namespace Yc
|
||||
{
|
||||
if (!silent)
|
||||
{
|
||||
addMessage(ChatUser::system, (*it)->name(), (*it)->color());
|
||||
addMessage(ChatUser::system, std::string("leaved_chat"), (*it)->name(), (*it)->color());
|
||||
}
|
||||
_users.erase(it);
|
||||
break;
|
||||
@@ -123,7 +166,7 @@ namespace Yc
|
||||
{
|
||||
if (!silent)
|
||||
{
|
||||
addMessage(ChatUser::system, (*it)->name(), (*it)->color());
|
||||
addMessage(ChatUser::system, std::string("leaved_chat"), (*it)->name(), (*it)->color());
|
||||
}
|
||||
_users.erase(it);
|
||||
break;
|
||||
@@ -164,6 +207,10 @@ namespace Yc
|
||||
}
|
||||
_users.push_back(user);
|
||||
user->setParent(shared_from_this());
|
||||
|
||||
// Sende aktuelle Userliste an den User nach Raumwechsel
|
||||
Json::Value currentUserList = userList();
|
||||
user->sendMsg(ChatUser::userListe, currentUserList, "", "");
|
||||
}
|
||||
|
||||
bool ChatRoom::userToNewRoom(std::shared_ptr<ChatUser> user, std::string newRoom, std::string password)
|
||||
@@ -188,6 +235,7 @@ namespace Yc
|
||||
{
|
||||
Json::Value jsonUser = Json::objectValue;
|
||||
jsonUser["name"] = user->name();
|
||||
jsonUser["color"] = user->color();
|
||||
users.append(jsonUser);
|
||||
}
|
||||
return users;
|
||||
@@ -243,6 +291,18 @@ namespace Yc
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<ChatUser> ChatRoom::findUserByName(std::string userName)
|
||||
{
|
||||
for (auto &user : _users)
|
||||
{
|
||||
if (userName == user->name())
|
||||
{
|
||||
return user;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ChatRoom::_handleDice()
|
||||
{
|
||||
if (((_type & rounds) == rounds))
|
||||
@@ -266,7 +326,8 @@ namespace Yc
|
||||
|
||||
void ChatRoom::_initRound()
|
||||
{
|
||||
if (_users.size() == 2)
|
||||
// Nur in Räumen mit Runden & Würfeln ankündigen
|
||||
if (_users.size() == 2 && ((_type & rounds) == rounds) && ((_type & dice) == dice))
|
||||
{
|
||||
_lastRoundEnd = time(NULL);
|
||||
addMessage(ChatUser::system, "next_round_starts_soon");
|
||||
@@ -293,5 +354,245 @@ namespace Yc
|
||||
return _name;
|
||||
}
|
||||
|
||||
// Neue Würfel-Funktionen
|
||||
bool ChatRoom::startDiceGame(int rounds, std::shared_ptr<ChatUser> admin)
|
||||
{
|
||||
if (!_isUserAdmin(admin)) {
|
||||
return false; // Kein Admin
|
||||
}
|
||||
|
||||
if (_diceGameRunning) {
|
||||
return false; // Spiel läuft bereits
|
||||
}
|
||||
|
||||
if (!canDice()) {
|
||||
return false; // Raum unterstützt kein Würfeln
|
||||
}
|
||||
|
||||
_diceGameRunning = true;
|
||||
_currentRound = 1;
|
||||
_totalRounds = rounds;
|
||||
_gameStartTime = std::chrono::steady_clock::now();
|
||||
_gameResults.clear();
|
||||
|
||||
// Alle User für das Spiel vorbereiten
|
||||
for (auto& user : _users) {
|
||||
_gameResults[user->name()] = std::vector<DiceResult>();
|
||||
_hasRolledThisRound[user->name()] = false;
|
||||
}
|
||||
|
||||
// Erste Runde starten
|
||||
_startDiceRound();
|
||||
|
||||
// Nachricht an alle senden
|
||||
Json::Value msg = Json::objectValue;
|
||||
msg["tr"] = "dice_game_started";
|
||||
msg["rounds"] = rounds;
|
||||
msg["admin"] = admin->name();
|
||||
addMessage(ChatUser::system, msg, "", "");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatRoom::rollDice(std::shared_ptr<ChatUser> user, int diceValue)
|
||||
{
|
||||
if (!_diceGameRunning) {
|
||||
return false; // Kein Spiel aktiv
|
||||
}
|
||||
|
||||
if (diceValue < 1 || diceValue > 6) {
|
||||
return false; // Ungültiger Würfelwert
|
||||
}
|
||||
|
||||
std::string userName = user->name();
|
||||
|
||||
if (_hasRolledThisRound[userName]) {
|
||||
return false; // Bereits gewürfelt
|
||||
}
|
||||
|
||||
// Würfelwert speichern
|
||||
DiceResult result;
|
||||
result.userName = userName;
|
||||
result.diceValue = diceValue;
|
||||
result.rollTime = std::chrono::steady_clock::now();
|
||||
result.valid = true;
|
||||
|
||||
_gameResults[userName].push_back(result);
|
||||
_hasRolledThisRound[userName] = true;
|
||||
|
||||
// Nachricht an alle senden
|
||||
Json::Value msg = Json::objectValue;
|
||||
msg["tr"] = "dice_rolled";
|
||||
msg["user"] = userName;
|
||||
msg["value"] = diceValue;
|
||||
msg["round"] = _currentRound;
|
||||
addMessage(ChatUser::dice, msg, userName, user->color());
|
||||
|
||||
// Prüfen ob alle gewürfelt haben
|
||||
bool allRolled = true;
|
||||
for (auto& pair : _hasRolledThisRound) {
|
||||
if (!pair.second) {
|
||||
allRolled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allRolled) {
|
||||
// Alle haben gewürfelt, Runde beenden
|
||||
_endDiceRound();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChatRoom::endDiceGame()
|
||||
{
|
||||
if (!_diceGameRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
_diceGameRunning = false;
|
||||
_showGameResults();
|
||||
|
||||
// Nachricht an alle senden
|
||||
Json::Value msg = Json::objectValue;
|
||||
msg["tr"] = "dice_game_ended";
|
||||
addMessage(ChatUser::system, msg, "", "");
|
||||
}
|
||||
|
||||
void ChatRoom::_startDiceRound()
|
||||
{
|
||||
if (_currentRound > _totalRounds) {
|
||||
endDiceGame();
|
||||
return;
|
||||
}
|
||||
|
||||
_roundStartTime = std::chrono::steady_clock::now();
|
||||
|
||||
// Alle User für neue Runde zurücksetzen
|
||||
for (auto& pair : _hasRolledThisRound) {
|
||||
pair.second = false;
|
||||
}
|
||||
|
||||
// Nachricht an alle senden
|
||||
Json::Value msg = Json::objectValue;
|
||||
msg["tr"] = "dice_round_started";
|
||||
msg["round"] = _currentRound;
|
||||
msg["total_rounds"] = _totalRounds;
|
||||
addMessage(ChatUser::system, msg, "", "");
|
||||
|
||||
// Timer für 15 Sekunden starten
|
||||
_startRoundTimer();
|
||||
}
|
||||
|
||||
void ChatRoom::_endDiceRound()
|
||||
{
|
||||
// Ungültige Ergebnisse für User die nicht gewürfelt haben
|
||||
for (auto& pair : _hasRolledThisRound) {
|
||||
if (!pair.second) {
|
||||
DiceResult result;
|
||||
result.userName = pair.first;
|
||||
result.diceValue = 0;
|
||||
result.rollTime = std::chrono::steady_clock::now();
|
||||
result.valid = false;
|
||||
_gameResults[pair.first].push_back(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Nachricht an alle senden
|
||||
Json::Value msg = Json::objectValue;
|
||||
msg["tr"] = "dice_round_ended";
|
||||
msg["round"] = _currentRound;
|
||||
addMessage(ChatUser::system, msg, "", "");
|
||||
|
||||
_currentRound++;
|
||||
|
||||
if (_currentRound <= _totalRounds) {
|
||||
// Nächste Runde starten
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2)); // 2 Sekunden Pause
|
||||
_startDiceRound();
|
||||
} else {
|
||||
// Spiel beenden
|
||||
endDiceGame();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::_startRoundTimer()
|
||||
{
|
||||
_roundTimerThread = std::thread([this]() {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(15));
|
||||
|
||||
// Prüfen ob Runde noch läuft
|
||||
if (_diceGameRunning && _currentRound <= _totalRounds) {
|
||||
_endDiceRound();
|
||||
}
|
||||
});
|
||||
_roundTimerThread.detach();
|
||||
}
|
||||
|
||||
void ChatRoom::_showGameResults()
|
||||
{
|
||||
Json::Value results = Json::objectValue;
|
||||
results["tr"] = "dice_game_results";
|
||||
results["total_rounds"] = _totalRounds;
|
||||
|
||||
Json::Value userResults = Json::arrayValue;
|
||||
for (auto& pair : _gameResults) {
|
||||
Json::Value userResult = Json::objectValue;
|
||||
userResult["user"] = pair.first;
|
||||
|
||||
Json::Value rounds = Json::arrayValue;
|
||||
int totalScore = 0;
|
||||
int validRolls = 0;
|
||||
|
||||
for (auto& result : pair.second) {
|
||||
Json::Value round = Json::objectValue;
|
||||
round["round"] = rounds.size() + 1;
|
||||
round["value"] = result.diceValue;
|
||||
round["valid"] = result.valid;
|
||||
rounds.append(round);
|
||||
|
||||
if (result.valid) {
|
||||
totalScore += result.diceValue;
|
||||
validRolls++;
|
||||
}
|
||||
}
|
||||
|
||||
userResult["rounds"] = rounds;
|
||||
userResult["total_score"] = totalScore;
|
||||
userResult["valid_rolls"] = validRolls;
|
||||
userResult["average"] = validRolls > 0 ? (double)totalScore / validRolls : 0.0;
|
||||
|
||||
userResults.append(userResult);
|
||||
}
|
||||
|
||||
results["user_results"] = userResults;
|
||||
addMessage(ChatUser::result, results, "", "");
|
||||
}
|
||||
|
||||
bool ChatRoom::_isUserAdmin(std::shared_ptr<ChatUser> user) const
|
||||
{
|
||||
// Einfache Admin-Prüfung: Erster User im Raum ist Admin
|
||||
// In einer echten Implementierung würde man hier Rechte aus der Datenbank prüfen
|
||||
if (_users.empty()) return false;
|
||||
return _users[0] == user;
|
||||
}
|
||||
|
||||
void ChatRoom::reloadRoomList()
|
||||
{
|
||||
// Neue Raumliste vom Server holen
|
||||
Json::Value roomList = _parent->jsonRoomList();
|
||||
|
||||
// An alle User im Raum senden
|
||||
for (auto& user : _users) {
|
||||
user->sendMsg(ChatUser::roomList, roomList, "", "");
|
||||
}
|
||||
|
||||
// System-Nachricht an alle senden
|
||||
Json::Value msg = Json::objectValue;
|
||||
msg["tr"] = "room_list_reloaded";
|
||||
addMessage(ChatUser::system, msg, "", "");
|
||||
}
|
||||
|
||||
} // namespace Lib
|
||||
} // namespace Yc
|
||||
|
||||
Reference in New Issue
Block a user