Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions RetroChessPlugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "gui/RetroChessChatWidgetHolder.h"
#include <retroshare-gui/RsAutoUpdatePage.h>

#include <retroshare/rsgxstunnel.h>
#include <retroshare/rsplugin.h>
#include <retroshare/rsversion.h>

Expand Down Expand Up @@ -77,19 +78,31 @@ void RetroChessPlugin::getPluginVersion(int& major, int& minor, int& build, int&
RetroChessPlugin::RetroChessPlugin()
{
qRegisterMetaType<RsPeerId>("RsPeerId");
qRegisterMetaType<RsGxsId>("RsGxsId");
mainpage = NULL ;
mRetroChess = NULL ;
mPlugInHandler = NULL;
mPeers = NULL;
config_page = NULL ;
mIcon = NULL ;
mGxsTunnels = NULL;
mIdentity = NULL;
mChats = NULL;

mRetroChessNotify = new RetroChessNotify;
}

void RetroChessPlugin::setInterfaces(RsPlugInInterfaces &interfaces)
{
mPeers = interfaces.mPeers;
mGxsTunnels = interfaces.mGxsTunnels;
mIdentity = interfaces.mIdentity;
mChats = interfaces.mChats;

if(mRetroChess)
{
mRetroChess->connectToGxsTunnelService(mGxsTunnels);
}
}

/*ConfigPage *RetroChessPlugin::qt_config_page() const
Expand Down Expand Up @@ -125,9 +138,10 @@ ChatWidgetHolder *RetroChessPlugin::qt_get_chat_widget_holder(ChatWidget *chatWi
{
case ChatWidget::CHATTYPE_PRIVATE:
return new RetroChessChatWidgetHolder(chatWidget, mRetroChessNotify);
case ChatWidget::CHATTYPE_DISTANT:
return new RetroChessChatWidgetHolder(chatWidget, mRetroChessNotify);
case ChatWidget::CHATTYPE_UNKNOWN:
case ChatWidget::CHATTYPE_LOBBY:
case ChatWidget::CHATTYPE_DISTANT:
break;
}

Expand All @@ -136,15 +150,23 @@ ChatWidgetHolder *RetroChessPlugin::qt_get_chat_widget_holder(ChatWidget *chatWi

p3Service *RetroChessPlugin::p3_service() const
{
if(mRetroChess == NULL)
rsRetroChess = mRetroChess = new p3RetroChess(mPlugInHandler,mRetroChessNotify) ; // , 3600 * 24 * 30 * 6); // 6 Months

return mRetroChess ;
if(mRetroChess == NULL)
{
// Create the service
rsRetroChess = mRetroChess = new p3RetroChess(mPlugInHandler, mRetroChessNotify);

// Register it for GXS Tunnels immediately if the interface is available
if (mGxsTunnels) {
mRetroChess->connectToGxsTunnelService(mGxsTunnels);
}
}
return mRetroChess;
}

void RetroChessPlugin::setPlugInHandler(RsPluginHandler *pgHandler)
{
mPlugInHandler = pgHandler;
mPlugInHandler = pgHandler;
// No need to register here if done in p3_service
}

QIcon *RetroChessPlugin::qt_icon() const
Expand Down
7 changes: 7 additions & 0 deletions RetroChessPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@

/*libretroshare"*/
#include <retroshare/rsplugin.h>
#include <retroshare/rsgxstunnel.h>
#include <retroshare/rsidentity.h>
#include <retroshare/rschats.h>

#include "gui/NEMainpage.h"

Expand Down Expand Up @@ -76,6 +79,10 @@ class RetroChessPlugin: public RsPlugin
mutable QIcon *mIcon;
mutable MainPage* mainpage ;

RsGxsTunnelService *mGxsTunnels;
RsIdentity *mIdentity;
RsChats *mChats;
RsGxsTunnelService::RsGxsTunnelClientService *mGxsTunnelClient;
RetroChessNotify *mRetroChessNotify ;
RetroChessGUIHandler *mRetroChessGUIHandler ;
};
Expand Down
32 changes: 31 additions & 1 deletion gui/NEMainpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ NEMainpage::NEMainpage(QWidget *parent, RetroChessNotify *notify) :

connect(mNotify, SIGNAL(NeMsgArrived(RsPeerId,QString)), this, SLOT(NeMsgArrived(RsPeerId,QString)));
connect(mNotify, SIGNAL(chessStart(RsPeerId)), this, SLOT(chessStart(RsPeerId)));
connect(mNotify, SIGNAL(chessStartGxs(RsGxsId)), this, SLOT(chessStartGxs(RsGxsId)));
connect(mNotify, SIGNAL(chessMoveGxs(RsGxsId,int,int,int)), this, SLOT(chessMoveGxs(RsGxsId,int,int,int)));
connect(ui->friendSelectionWidget, SIGNAL(itemSelectionChanged()), this, SLOT(friendSelectionChanged()));

// enable/disable the invite button
Expand All @@ -75,7 +77,23 @@ NEMainpage::~NEMainpage()

void NEMainpage::chessStart(const RsPeerId &peer_id)
{
create_chess_window(peer_id.toStdString(), 0);
create_chess_window(peer_id.toStdString(), 1);
}

void NEMainpage::chessStartGxs(const RsGxsId &gxs_id)
{
create_chess_window_gxs(gxs_id, 0);
}

void NEMainpage::chessMoveGxs(const RsGxsId &gxs_id, int col, int row, int count)
{
std::string key = gxs_id.toStdString();
if (activeGames.find(key) != activeGames.end()) {
RetroChessWindow* rcw = activeGames.value(key);
rcw->validate_tile(row, col, count);
} else {
std::cerr << "RetroChess: Received GXS move but no active game for " << key << std::endl;
}
}

// decode received message here
Expand Down Expand Up @@ -178,6 +196,18 @@ void NEMainpage::create_chess_window(std::string peer_id, int player_id)
ui->active_games->addItem(QString::fromStdString(peer_id));
}

void NEMainpage::create_chess_window_gxs(const RsGxsId &gxs_id, int player_id)
{
// Open the window with the GXS constructor
RetroChessWindow *win = new RetroChessWindow(gxs_id, player_id);
win->show();

// Track the game so GXS moves can be routed to it
std::string key = gxs_id.toStdString();
activeGames.insert(key, win);
ui->active_games->addItem(QString::fromStdString(key));
}

// enable the invite button when selected a friend
void NEMainpage::enable_inviteButton()
{
Expand Down
3 changes: 3 additions & 0 deletions gui/NEMainpage.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ private slots:
void friendSelectionChanged();
void NeMsgArrived(const RsPeerId &peer_id, QString str);
void chessStart(const RsPeerId &peer_id);
void chessStartGxs(const RsGxsId &gxs_id);
void chessMoveGxs(const RsGxsId &gxs_id, int col, int row, int count);

void on_broadcastButton_clicked();

Expand All @@ -78,6 +80,7 @@ private slots:

QMap<std::string, RetroChessWindow*> activeGames;
void create_chess_window(std::string peer_id, int player_id);
void create_chess_window_gxs(const RsGxsId &gxs_id, int player_id);
};

#endif // NEMAINPAGE_H
180 changes: 166 additions & 14 deletions gui/RetroChessChatWidgetHolder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@
#include "interface/rsRetroChess.h"

#include "gui/chat/ChatWidget.h"
#include <retroshare/rschats.h>

#include "RetroChessChatWidgetHolder.h"

#include <retroshare/rsidentity.h>
#include <retroshare/rsstatus.h>
#include <retroshare/rspeers.h>

Expand All @@ -41,7 +43,6 @@ RetroChessChatWidgetHolder::RetroChessChatWidgetHolder(ChatWidget *chatWidget, R
QIcon icon ;
icon.addPixmap(QPixmap(IMAGE_RetroChess)) ;


playChessButton = new QToolButton ;
playChessButton->setIcon(icon) ;
playChessButton->setToolTip(tr("Invite Friend to Chess"));
Expand All @@ -51,6 +52,11 @@ RetroChessChatWidgetHolder::RetroChessChatWidgetHolder(ChatWidget *chatWidget, R
mChatWidget->addChatBarWidget(playChessButton);
connect(playChessButton, SIGNAL(clicked()), this, SLOT(chessPressed()));
connect(notify, SIGNAL(chessInvited(RsPeerId)), this, SLOT(chessnotify(RsPeerId)));
connect(notify, SIGNAL(chessInvitedGxs(RsGxsId)), this, SLOT(chessnotifyGxs(RsGxsId)));
// When the p3RetroChess service detects the tunnel is CONNECTED,
// it calls notifyGxsTunnelReady, which emits this signal:
connect(notify, SIGNAL(gxsTunnelReady(RsGxsId)), this, SLOT(handleGxsTunnelReady(RsGxsId)));
connect(notify, SIGNAL(gxsTunnelClosed(RsGxsId)), this, SLOT(handleGxsTunnelClosed(RsGxsId)));

}

Expand Down Expand Up @@ -109,34 +115,180 @@ void RetroChessChatWidgetHolder::chessnotify(RsPeerId from_peer_id)
}
}

void RetroChessChatWidgetHolder::chessPressed()
void RetroChessChatWidgetHolder::chessnotifyGxs(const RsGxsId &from_gxs_id)
{
RsPeerId peer_id = mChatWidget->getChatId().toPeerId();//TODO support GXSID
if (rsRetroChess->hasInviteFrom(peer_id))
{
ChatId chatId = mChatWidget->getChatId();

// Only handle distant (GXS) chats
if (!chatId.isDistantChatId()) {
return;
}

// Verify the invite is specifically for THIS chat window.
// Each distant chat window has a unique tunnel — check the remote GXS ID matches.
DistantChatPeerInfo dcpinfo;
if (!rsChats->getDistantChatStatus(chatId.toDistantChatId(), dcpinfo)) {
return; // Can't identify this window's remote peer
}
if (dcpinfo.to_id != from_gxs_id) {
return; // This invite is for a different chat window
}

if (!mChatWidget) {
return;
}

// Get a display name for the button
QString buttonName = QString::fromStdString(from_gxs_id.toStdString()).left(8);

// Clear any old accept buttons to avoid duplicates
button_map::iterator it = buttonMapTakeChess.begin();
while (it != buttonMapTakeChess.end()) {
it = buttonMapTakeChess.erase(it);
}

// Add the system message and the "Accept" button to the chat history
mChatWidget->addChatMsg(true, tr("Chess Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime(),
tr("%1 is inviting you to start Chess via GXS. Accept?").arg(buttonName),
ChatWidget::MSGTYPE_SYSTEM);

RSButtonOnText *button = mChatWidget->getNewButtonOnTextBrowser(tr("Accept GXS Invite"));
button->setToolTip(tr("Accept Chess Invitation"));

button->setStyleSheet(QString("border: 1px solid #199909;")
.append("font-size: 12pt; color: white;")
.append("min-width: 128px; min-height: 24px;")
.append("border-radius: 6px;")
.append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, "
"stop: 0 #22c70d, stop: 1 #116a06);"));

button->updateImage();

connect(button, SIGNAL(clicked()), this, SLOT(chessStart()));
connect(button, SIGNAL(mouseEnter()), this, SLOT(botMouseEnter()));
connect(button, SIGNAL(mouseLeave()), this, SLOT(botMouseLeave()));

buttonMapTakeChess.insert(buttonName, button);
}

rsRetroChess->acceptedInvite(peer_id);
mRetroChessNotify->notifyChessStart(peer_id);

void RetroChessChatWidgetHolder::chessPressed()
{
ChatId chatId = mChatWidget->getChatId();
QString peerName;
if (chatId.isDistantChatId()) {
// sendInvite_chat() handles everything:
// - if the GXS tunnel is ready: requests tunnel + queues invite immediately
// - if not ready yet: stores chatId and retries automatically on each tick()
rsRetroChess->sendInvite_chat(chatId);

DistantChatPeerInfo dcpinfo;
if (rsChats->getDistantChatStatus(chatId.toDistantChatId(), dcpinfo)
&& !dcpinfo.to_id.isNull()) {
peerName = QString::fromStdString(dcpinfo.to_id.toStdString()).left(8);
mChatWidget->addChatMsg(true, tr("RetroChess"), QDateTime::currentDateTime(),
QDateTime::currentDateTime(),
tr("Chess invite queued for %1 — will send when connection is ready.").arg(peerName),
ChatWidget::MSGTYPE_SYSTEM);
} else {
// Tunnel not up yet — service will retry automatically
mChatWidget->addChatMsg(true, tr("RetroChess"), QDateTime::currentDateTime(),
QDateTime::currentDateTime(),
tr("Chess invite queued — connecting to friend, will send automatically..."),
ChatWidget::MSGTYPE_SYSTEM);
}
return;
} else {
RsPeerId peer_id = chatId.toPeerId();

}
rsRetroChess->sendInvite(peer_id);
if (rsRetroChess->hasInviteFrom(peer_id)){
rsRetroChess->acceptedInvite(peer_id);
mRetroChessNotify->notifyChessStart(peer_id);
return;
}

rsRetroChess->sendInvite(peer_id);

QString peerName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str());
peerName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str());
}
mChatWidget->addChatMsg(true, tr("Chess Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime()
, tr("You're now inviting %1 to play Chess").arg(peerName), ChatWidget::MSGTYPE_SYSTEM);

}


void RetroChessChatWidgetHolder::chessStart()
{
RsPeerId peer_id = mChatWidget->getChatId().toPeerId();//TODO support GXSID
ChatId chatId = mChatWidget->getChatId();
if (chatId.isDistantChatId()) {
// Remote side accepting an invite:
// The tunnel is already open (the invite arrived over it).
// Call acceptedInviteGxs() which will send chess_accept over the existing tunnel.
DistantChatPeerInfo dcpinfo;
if (!rsChats->getDistantChatStatus(chatId.toDistantChatId(), dcpinfo)) {
std::cerr << "RetroChess: Failed to resolve distant chat status" << std::endl;
return;
}
RsGxsId remoteGxsId = dcpinfo.to_id;

rsRetroChess->acceptedInviteGxs(remoteGxsId);

rsRetroChess->acceptedInvite(peer_id);
mRetroChessNotify->notifyChessStart(peer_id);
// Open the chess window immediately — we're the server side, tunnel is already up
mRetroChessNotify->notifyChessStartGxs(remoteGxsId);
if (playChessButton) playChessButton->hide();

} else {
RsPeerId peer_id = chatId.toPeerId();
rsRetroChess->acceptedInvite(peer_id);
mRetroChessNotify->notifyChessStart(peer_id);
}
return;
}


void RetroChessChatWidgetHolder::handleGxsTunnelReady(const RsGxsId &gxs_id)
{
ChatId chatId = mChatWidget->getChatId();
if (chatId.isDistantChatId()) {
// Verify this tunnel is for the current chat
DistantChatPeerInfo dcpinfo;
if (rsChats->getDistantChatStatus(chatId.toDistantChatId(), dcpinfo)) {
if (dcpinfo.to_id == gxs_id) {
// Now the tunnel is safe to use. Open the window.
mRetroChessNotify->notifyChessStartGxs(gxs_id);
if (playChessButton) playChessButton->hide();
}
}
}
}

void RetroChessChatWidgetHolder::handleGxsTunnelClosed(const RsGxsId &gxs_id)
{
ChatId chatId = mChatWidget->getChatId();
if (!chatId.isDistantChatId())
return;

// Check that this closure is for the remote peer of THIS chat window
DistantChatPeerInfo dcpinfo;
if (rsChats->getDistantChatStatus(chatId.toDistantChatId(), dcpinfo)) {
if (dcpinfo.to_id != gxs_id)
return; // Belongs to a different chat window
}

// Restore the button so the user can start a new game
if (playChessButton) {
playChessButton->show();
}

if (mChatWidget) {
mChatWidget->addChatMsg(true, tr("RetroChess"),
QDateTime::currentDateTime(),
QDateTime::currentDateTime(),
tr("Connection to chess partner was lost. You can invite them again."),
ChatWidget::MSGTYPE_SYSTEM);
}
}


void RetroChessChatWidgetHolder::botMouseEnter()
{
RSButtonOnText *source = qobject_cast<RSButtonOnText *>(QObject::sender());
Expand Down
Loading