From 60b9839fd7e72b8ad0700195114e3d548fef5cb4 Mon Sep 17 00:00:00 2001 From: notify Date: Mon, 2 May 2022 14:00:47 +0800 Subject: [PATCH] Disable sync (#21) * fix running from running room * fix: ~serverplayer() * since room player's id won't change anymore, don't use :getId() * we won't access lua from other thread, so drop the mutex * bugfix --- lua/client/client.lua | 6 ++- lua/server/gamelogic.lua | 12 +++++ lua/server/room.lua | 66 ++++++--------------------- lua/server/serverplayer.lua | 6 +-- packages/standard/game_rule.lua | 6 +-- qml/main.qml | 6 ++- src/core/player.cpp | 4 ++ src/core/player.h | 3 +- src/network/router.cpp | 2 - src/server/room.cpp | 79 +++++++++++---------------------- src/server/room.h | 3 -- src/server/server.cpp | 17 ++++--- src/server/server.h | 1 + src/server/serverplayer.cpp | 20 +++++---- src/server/serverplayer.h | 1 + src/ui/qmlbackend.cpp | 3 +- 16 files changed, 97 insertions(+), 138 deletions(-) diff --git a/lua/client/client.lua b/lua/client/client.lua index 8d0dfea4..e6d550d4 100644 --- a/lua/client/client.lua +++ b/lua/client/client.lua @@ -43,7 +43,11 @@ fk.client_callback["Setup"] = function(jsonData) self:setScreenName(name) self:setAvatar(avatar) Self = ClientPlayer:new(fk.Self) - table.insert(ClientInstance.players, Self) +end + +fk.client_callback["EnterRoom"] = function(jsonData) + ClientInstance.players = {Self} + ClientInstance:notifyUI("EnterRoom", jsonData) end fk.client_callback["AddPlayer"] = function(jsonData) diff --git a/lua/server/gamelogic.lua b/lua/server/gamelogic.lua index 41adc7d6..d21e5baf 100644 --- a/lua/server/gamelogic.lua +++ b/lua/server/gamelogic.lua @@ -150,10 +150,22 @@ function GameLogic:action() self:trigger(fk.DrawInitialCards, p, { num = 4 }) end + local function checkNoHuman() + for _, p in ipairs(room.players) do + if p.serverplayer:getStateString() == "online" then + return false + end + end + return true + end + while true do self:trigger(fk.TurnStart, room.current) if room.game_finished then break end room.current = room.current:getNextAlive() + if checkNoHuman() then + room:gameOver() + end end end diff --git a/lua/server/room.lua b/lua/server/room.lua index aab919bd..215052c6 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -52,7 +52,6 @@ end function Room:run() for _, p in fk.qlist(self.room:getPlayers()) do local player = ServerPlayer:new(p) - player.state = p:getStateString() player.room = self table.insert(self.players, player) end @@ -74,7 +73,7 @@ end ---@param property string function Room:notifyProperty(p, player, property) p:doNotify("PropertyUpdate", json.encode{ - player:getId(), + player.id, property, player[property], }) @@ -134,7 +133,7 @@ function Room:notifyMoveFocus(players, command) local ids = {} for _, p in ipairs(players) do - table.insert(ids, p:getId()) + table.insert(ids, p.id) end self:doBroadcastNotify("MoveFocus", json.encode{ @@ -165,7 +164,7 @@ function Room:adjustSeats() local player_circle = {} for i = 1, #self.players do self.players[i].seat = i - table.insert(player_circle, self.players[i]:getId()) + table.insert(player_circle, self.players[i].id) end self:doBroadcastNotify("ArrangeSeats", json.encode(player_circle)) @@ -233,7 +232,7 @@ function Room:notifyMoveCards(players, card_moves, forceVisible) -- FIXME: move.moveInfo is an array, fix this move.moveVisible = (forceVisible) -- if move is relevant to player, it should be open - or ((move.from == p:getId()) or (move.to == p:getId() and move.toArea ~= Card.PlayerSpecial)) + or ((move.from == p.id) or (move.to == p.id and move.toArea ~= Card.PlayerSpecial)) -- cards move from/to equip/judge/discard/processing should be open or move.moveInfo.fromArea == Card.PlayerEquip or move.toArea == Card.PlayerEquip @@ -364,10 +363,10 @@ function Room:drawCards(player, num, skillName, fromPlace) local topCards = self:getNCards(num, fromPlace) self:moveCards({ ids = topCards, - to = player:getId(), + to = player.id, toArea = Card.PlayerHand, moveReason = fk.ReasonDraw, - proposer = player:getId(), + proposer = player.id, skillName = skillName, }) @@ -394,10 +393,10 @@ function Room:askForDiscard(player, minNum, maxNum, includeEquip, skillName) self:moveCards({ ids = toDiscard, - from = player:getId(), + from = player.id, toArea = Card.DiscardPile, moveReason = fk.ReasonDiscard, - proposer = player:getId(), + proposer = player.id, skillName = skillName }) end @@ -408,7 +407,7 @@ function Room:getPlayerById(id) assert(type(id) == "number") for _, p in ipairs(self.players) do - if p:getId() == id then + if p.id == id then return p end end @@ -453,7 +452,7 @@ end function Room:getOtherPlayers(player, sortBySeat) local alivePlayers = self:getAlivePlayers(sortBySeat) for _, p in ipairs(alivePlayers) do - if p:getId() == player:getId() then + if p.id == player.id then table.removeOne(alivePlayers, player) break end @@ -568,7 +567,7 @@ function Room:changeHp(player, num, reason, skillName, damageStruct) if player.hp < 1 then ---@type DyingStruct local dyingStruct = { - who = player:getId(), + who = player.id, damage = damageStruct, } self:enterDying(dyingStruct) @@ -624,7 +623,7 @@ function Room:changeMaxHp(player, num) end if player.maxHp == 0 then - self:killPlayer({ who = player:getId() }) + self:killPlayer({ who = player.id }) end self.logic:trigger(fk.MaxHpChanged, player, { num = num }) @@ -718,7 +717,7 @@ function Room:enterDying(dyingStruct) if dyingPlayer.hp < 1 then ---@type DeathStruct local deathData = { - who = dyingPlayer:getId(), + who = dyingPlayer.id, damage = dyingStruct.damage, } self:killPlayer(deathData) @@ -976,45 +975,6 @@ fk.room_callback["AddRobot"] = function(jsonData) end end -fk.room_callback["PlayerRunned"] = function(jsonData) - -- jsonData: [ int runner_id, int robot_id ] - -- note: this function is not called by Router. - -- note: when this function is called, the room must be started - local data = json.decode(jsonData) - local runner = data[1] - local robot = data[2] - for _, p in ipairs(RoomInstance.players) do - if p:getId() == runner then - p.serverplayer = RoomInstance.room:findPlayer(robot) - p.id = p.serverplayer:getId() - end - end -end - -fk.room_callback["PlayerStateChanged"] = function(jsonData) - -- jsonData: [ int uid, string stateString ] - -- note: this function is not called by Router. - -- note: when this function is called, the room must be started - local data = json.decode(jsonData) - local id = data[1] - local stateString = data[2] - RoomInstance:getPlayerById(id).state = stateString -end - -fk.room_callback["RoomDeleted"] = function(jsonData) - debug.sethook(function () - error("Room is deleted when running") - end, "l") -end - -fk.room_callback["DoLuaScript"] = function(jsonData) - -- jsonData: [ int uid, string luaScript ] - -- warning: only use this in debugging mode. - if not DebugMode then return end - local data = json.decode(jsonData) - assert(load(data[2]))() -end - function CreateRoom(_room) RoomInstance = Room:new(_room) end diff --git a/lua/server/serverplayer.lua b/lua/server/serverplayer.lua index debf21bd..c6def962 100644 --- a/lua/server/serverplayer.lua +++ b/lua/server/serverplayer.lua @@ -15,6 +15,7 @@ function ServerPlayer:initialize(_self) Player.initialize(self) self.serverplayer = _self self.id = _self:getId() + self.state = _self:getStateString() self.room = nil self.next = nil @@ -27,11 +28,6 @@ function ServerPlayer:initialize(_self) self.phases = {} end ----@return integer -function ServerPlayer:getId() - return self.id -end - ---@param command string ---@param jsonData string function ServerPlayer:doNotify(command, jsonData) diff --git a/packages/standard/game_rule.lua b/packages/standard/game_rule.lua index d0f864bd..bee2d743 100644 --- a/packages/standard/game_rule.lua +++ b/packages/standard/game_rule.lua @@ -33,7 +33,7 @@ GameRule = fk.CreateTriggerSkill{ player:addCards(Player.Hand, cardIds) local move_to_notify = {} ---@type CardsMoveStruct move_to_notify.toArea = Card.PlayerHand - move_to_notify.to = player:getId() + move_to_notify.to = player.id move_to_notify.moveInfo = {} for _, id in ipairs(cardIds) do table.insert(move_to_notify.moveInfo, @@ -85,14 +85,14 @@ GameRule = fk.CreateTriggerSkill{ [Player.Play] = function() while not player.dead do room:notifyMoveFocus(player, "PlayCard") - local result = room:doRequest(player, "PlayCard", player:getId()) + local result = room:doRequest(player, "PlayCard", player.id) if result == "" then break end local data = json.decode(result) local card = data.card local targets = data.targets local use = {} ---@type CardUseStruct - use.from = player:getId() + use.from = player.id use.tos = {} for _, target in ipairs(targets) do table.insert(use.tos, { target }) diff --git a/qml/main.qml b/qml/main.qml index 74c0190e..3e4c3c21 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -1,6 +1,6 @@ import QtQuick 2.15 import QtQuick.Controls 2.0 -import QtQuick.Window 2.0 +import QtQuick.Window 2.15 import "Logic.js" as Logic import "Pages" @@ -130,4 +130,8 @@ Window { } } } + + onClosing: { + Backend.quitLobby(); + } } diff --git a/src/core/player.cpp b/src/core/player.cpp index f4d46200..a9998427 100644 --- a/src/core/player.cpp +++ b/src/core/player.cpp @@ -56,6 +56,8 @@ QString Player::getStateString() const return QStringLiteral("online"); case Trust: return QStringLiteral("trust"); + case Run: + return QStringLiteral("run"); case Robot: return QStringLiteral("robot"); case Offline: @@ -77,6 +79,8 @@ void Player::setStateString(const QString &state) setState(Online); else if (state == QStringLiteral("trust")) setState(Trust); + else if (state == QStringLiteral("run")) + setState(Run); else if (state == QStringLiteral("robot")) setState(Robot); else if (state == QStringLiteral("offline")) diff --git a/src/core/player.h b/src/core/player.h index fa25a949..6ccb39b6 100644 --- a/src/core/player.h +++ b/src/core/player.h @@ -10,7 +10,8 @@ public: enum State{ Invalid, Online, - Trust, // Trust or run + Trust, + Run, Robot, // only for real robot Offline }; diff --git a/src/network/router.cpp b/src/network/router.cpp index c7eb0696..5db60c39 100644 --- a/src/network/router.cpp +++ b/src/network/router.cpp @@ -161,9 +161,7 @@ void Router::handlePacket(const QByteArray& rawPacket) arr.prepend(player->getId()); Room *room = player->getRoom(); - room->lockLua(__FUNCTION__); room->callLua(command, QJsonDocument(arr).toJson()); - room->unlockLua(__FUNCTION__); } } else if (type & TYPE_REQUEST) { diff --git a/src/server/room.cpp b/src/server/room.cpp index 64f89e0a..34592943 100644 --- a/src/server/room.cpp +++ b/src/server/room.cpp @@ -32,8 +32,6 @@ Room::~Room() { // TODO if (isRunning()) { - callLua("RoomDeleted", ""); - unlockLua(__FUNCTION__); wait(); } lua_close(L); @@ -173,44 +171,39 @@ void Room::addRobot(ServerPlayer *player) void Room::removePlayer(ServerPlayer *player) { - players.removeOne(player); - emit playerRemoved(player); + if (!gameStarted) { + players.removeOne(player); + emit playerRemoved(player); - if (isLobby()) return; - - if (gameStarted) { - // TODO: if the player is died.. - - // create robot first - ServerPlayer *robot = new ServerPlayer(this); - robot->setState(Player::Robot); - robot->setId(robot_id); - robot->setAvatar(player->getAvatar()); - robot->setScreenName(QString("COMP-%1").arg(robot_id)); - robot_id--; - - players.append(robot); - - // tell lua & clients - QJsonArray jsonData; - jsonData << player->getId(); - jsonData << robot->getId(); - callLua("PlayerRunned", QJsonDocument(jsonData).toJson()); - doBroadcastNotify(getPlayers(), "PlayerRunned", QJsonDocument(jsonData).toJson()); - runned_players << player->getId(); - - // FIXME: abortRequest here will result crash - // but if dont abort and room is abandoned, the main thread will wait until replyed - // player->abortRequest(); - } else { QJsonArray jsonData; jsonData << player->getId(); doBroadcastNotify(getPlayers(), "RemovePlayer", QJsonDocument(jsonData).toJson()); + + if (isLobby()) return; + } else { + // TODO: if the player is died.. + + // change the socket and state to runned player + ClientSocket *socket = player->getSocket(); + player->setState(Player::Run); + + // and then create a new ServerPlayer for the runner + ServerPlayer *runner = new ServerPlayer(this); + runner->setSocket(socket); + connect(runner, &ServerPlayer::disconnected, server, &Server::onUserDisconnected); + connect(runner, &Player::stateChanged, server, &Server::onUserStateChanged); + runner->setScreenName(player->getScreenName()); + runner->setAvatar(player->getAvatar()); + runner->setId(player->getId()); + + // finally update Server's player list and clean + server->addPlayer(runner); + + emit playerRemoved(runner); + runner->abortRequest(); } if (isAbandoned()) { - // FIXME: do not delete room here - // create a new thread and delete the room emit abandoned(); } else if (player == owner) { setOwner(players.first()); @@ -283,28 +276,8 @@ void Room::gameOver() } } -void Room::lockLua(const QString &caller) -{ - if (!gameStarted) return; - lua_mutex.lock(); -#ifdef QT_DEBUG - //qDebug() << caller << "=> room->L is locked."; -#endif -} - -void Room::unlockLua(const QString &caller) -{ - if (!gameStarted) return; - lua_mutex.unlock(); -#ifdef QT_DEBUG - //qDebug() << caller << "=> room->L is unlocked."; -#endif -} - void Room::run() { gameStarted = true; - lockLua(__FUNCTION__); roomStart(); - unlockLua(__FUNCTION__); } diff --git a/src/server/room.h b/src/server/room.h index 9d05d3fa..0f8b9597 100644 --- a/src/server/room.h +++ b/src/server/room.h @@ -56,9 +56,6 @@ public: void roomStart(); LuaFunction startGame; - void lockLua(const QString &caller); - void unlockLua(const QString &caller); - signals: void abandoned(); diff --git a/src/server/server.cpp b/src/server/server.cpp index 8b451f64..1bc792b4 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -67,6 +67,15 @@ ServerPlayer *Server::findPlayer(int id) const return players.value(id); } +void Server::addPlayer(ServerPlayer *player) +{ + int id = player->getId(); + if (players.contains(id)) + players.remove(id); + + players.insert(id, player); +} + void Server::removePlayer(int id) { players.remove(id); } @@ -252,10 +261,4 @@ void Server::onUserDisconnected() } void Server::onUserStateChanged() -{ - ServerPlayer *player = qobject_cast(sender()); - QJsonArray arr; - arr << player->getId(); - arr << player->getStateString(); - player->getRoom()->callLua("PlayerStateChanged", QJsonDocument(arr).toJson()); -} +{} diff --git a/src/server/server.h b/src/server/server.h index 58101306..2040e412 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -21,6 +21,7 @@ public: Room *lobby() const; ServerPlayer *findPlayer(int id) const; + void addPlayer(ServerPlayer *player); void removePlayer(int id); void updateRoomList(); diff --git a/src/server/serverplayer.cpp b/src/server/serverplayer.cpp index a456dbea..fcb13589 100644 --- a/src/server/serverplayer.cpp +++ b/src/server/serverplayer.cpp @@ -21,7 +21,8 @@ ServerPlayer::~ServerPlayer() // now we are in lobby, so quit lobby room->removePlayer(this); } - server->removePlayer(getId()); + if (server->findPlayer(getId()) == this) + server->removePlayer(getId()); router->deleteLater(); } @@ -42,6 +43,11 @@ void ServerPlayer::setSocket(ClientSocket *socket) router->setSocket(socket); } +ClientSocket *ServerPlayer::getSocket() const +{ + return socket; +} + Server *ServerPlayer::getServer() const { return server; @@ -76,21 +82,20 @@ void ServerPlayer::abortRequest() QString ServerPlayer::waitForReply() { - room->unlockLua(__FUNCTION__); QString ret; - if (getState() != Player::Online) { - QThread::sleep(1); - ret = ""; + Player::State state = getState(); + if (state != Player::Online) { + if (state != Player::Run) + QThread::sleep(1); + ret = QString("__state=%1").arg(getStateString()); } else { ret = router->waitForReply(); } - room->lockLua(__FUNCTION__); return ret; } QString ServerPlayer::waitForReply(int timeout) { - room->unlockLua(__FUNCTION__); QString ret; if (getState() != Player::Online) { QThread::sleep(1); @@ -98,7 +103,6 @@ QString ServerPlayer::waitForReply(int timeout) } else { ret = router->waitForReply(timeout); } - room->lockLua(__FUNCTION__); return ret; } diff --git a/src/server/serverplayer.h b/src/server/serverplayer.h index b385b6bd..a8e34300 100644 --- a/src/server/serverplayer.h +++ b/src/server/serverplayer.h @@ -15,6 +15,7 @@ public: ~ServerPlayer(); void setSocket(ClientSocket *socket); + ClientSocket *getSocket() const; Server *getServer() const; Room *getRoom() const; diff --git a/src/ui/qmlbackend.cpp b/src/ui/qmlbackend.cpp index 5d702e8a..efcc99e8 100644 --- a/src/ui/qmlbackend.cpp +++ b/src/ui/qmlbackend.cpp @@ -58,7 +58,8 @@ void QmlBackend::joinServer(QString address) void QmlBackend::quitLobby() { - delete ClientInstance; + if (ClientInstance) + delete ClientInstance; } void QmlBackend::emitNotifyUI(const QString &command, const QString &jsonData) {