1 /*
2 This file is part of the KDE games library
3 SPDX-FileCopyrightText: 2001-2002 Andreas Beckermann <b_mann@gmx.de>
4 SPDX-FileCopyrightText: 2001 Martin Heni <kde at heni-online.de>
5
6 SPDX-License-Identifier: LGPL-2.0-only
7 */
8
9 #include "kgamechat.h"
10
11 // own
12 #include "../kchatbase_p.h"
13 #include "kgame.h"
14 #include "kplayer.h"
15 #include "kgameproperty.h"
16 #include "kgamemessage.h"
17 // KF
18 #include <KLocalizedString>
19 // Qt
20 #include <QMap>
21
22 //FIXME:
23 #define FIRST_ID 2 // first id, that is free of use, aka not defined above
24
25 class KGameChatPrivate : public KChatBasePrivate
26 {
27 public:
KGameChatPrivate(KChatBaseModel * model,KChatBaseItemDelegate * delegate,QWidget * parent)28 KGameChatPrivate(KChatBaseModel* model, KChatBaseItemDelegate* delegate, QWidget* parent)
29 : KChatBasePrivate(model, delegate, parent)
30 {
31 mFromPlayer = nullptr;
32 mGame = nullptr;
33
34 mToMyGroup = -1;
35 }
36
37 KGame* mGame;
38 KPlayer* mFromPlayer;
39 int mMessageId;
40
41
42 QMap<int, int> mSendId2PlayerId;
43 int mToMyGroup; // just as the above - but for the group, not for players
44 };
45
KGameChat(KGame * g,int msgid,QWidget * parent,KChatBaseModel * model,KChatBaseItemDelegate * delegate)46 KGameChat::KGameChat(KGame* g, int msgid, QWidget* parent, KChatBaseModel* model, KChatBaseItemDelegate* delegate)
47 : KChatBase(*new KGameChatPrivate(model, delegate, parent), parent, false)
48 {
49 init(g, msgid);
50 }
51
KGameChat(KGame * g,int msgid,KPlayer * fromPlayer,QWidget * parent,KChatBaseModel * model,KChatBaseItemDelegate * delegate)52 KGameChat::KGameChat(KGame* g, int msgid, KPlayer* fromPlayer, QWidget* parent, KChatBaseModel* model, KChatBaseItemDelegate* delegate)
53 : KChatBase(*new KGameChatPrivate(model, delegate, parent), parent, false)
54 {
55 init(g, msgid);
56 setFromPlayer(fromPlayer);
57 }
58
KGameChat(QWidget * parent)59 KGameChat::KGameChat(QWidget* parent)
60 : KChatBase(*new KGameChatPrivate(nullptr, nullptr, parent), parent, false)
61 {
62 init(nullptr, -1);
63 }
64
~KGameChat()65 KGameChat::~KGameChat()
66 {
67 qCDebug(GAMES_PRIVATE_KGAME) ;
68 }
69
init(KGame * g,int msgId)70 void KGameChat::init(KGame* g, int msgId)
71 {
72 qCDebug(GAMES_PRIVATE_KGAME) ;
73 setMessageId(msgId);
74
75 setKGame(g);
76 }
77
addMessage(int fromId,const QString & text)78 void KGameChat::addMessage(int fromId, const QString& text)
79 {
80 Q_D(KGameChat);
81
82 if (!d->mGame) {
83 qCWarning(GAMES_PRIVATE_KGAME) << "no KGame object has been set";
84 addMessage(i18n("Player %1", fromId), text);
85 } else {
86 KPlayer* p = d->mGame->findPlayer(fromId);
87 if (p) {
88 qCDebug(GAMES_PRIVATE_KGAME) << "adding message of player" << p->name() << "id=" << fromId;
89 addMessage(p->name(), text);
90 } else {
91 qCWarning(GAMES_PRIVATE_KGAME) << "Could not find player id" << fromId;
92 addMessage(i18nc("Unknown player", "Unknown"), text);
93 }
94 }
95 }
96
returnPressed(const QString & text)97 void KGameChat::returnPressed(const QString& text)
98 {
99 Q_D(KGameChat);
100
101 if (!d->mFromPlayer) {
102 qCWarning(GAMES_PRIVATE_KGAME) << ": You must set a player first!";
103 return;
104 }
105 if (!d->mGame) {
106 qCWarning(GAMES_PRIVATE_KGAME) << ": You must set a game first!";
107 return;
108 }
109
110 qCDebug(GAMES_PRIVATE_KGAME) << "from:" << d->mFromPlayer->id() << "==" << d->mFromPlayer->name();
111
112 int id = sendingEntry();
113
114 if (isToGroupMessage(id)) {
115 // note: there is currently no support for other groups than the players
116 // group! It might be useful to send to other groups, too
117 QString group = d->mFromPlayer->group();
118 qCDebug(GAMES_PRIVATE_KGAME) << "send to group" << group;
119 int sender = d->mFromPlayer->id();
120 d->mGame->sendGroupMessage(text, messageId(), sender, group);
121
122 //TODO
123 //AB: this message is never received!! we need to connect to
124 //KPlayer::networkData!!!
125 //TODO
126
127 } else {
128 int toPlayer = 0;
129 if (!isSendToAllMessage(id) && isToPlayerMessage(id)) {
130 toPlayer = playerId(id);
131 if (toPlayer == -1) {
132 qCCritical(GAMES_PRIVATE_KGAME) << ": don't know that player "
133 << "- internal ERROR";
134 }
135 }
136 int receiver = toPlayer;
137 int sender = d->mFromPlayer->id();
138 d->mGame->sendMessage(text, messageId(), receiver, sender);
139 }
140 }
141
setMessageId(int msgid)142 void KGameChat::setMessageId(int msgid)
143 {
144 Q_D(KGameChat);
145
146 d->mMessageId = msgid;
147 }
148
messageId() const149 int KGameChat::messageId() const
150 {
151 Q_D(const KGameChat);
152
153 return d->mMessageId;
154 }
155
isSendToAllMessage(int id) const156 bool KGameChat::isSendToAllMessage(int id) const
157 {
158 return (id == KChatBase::SendToAll);
159 }
160
isToGroupMessage(int id) const161 bool KGameChat::isToGroupMessage(int id) const
162 {
163 Q_D(const KGameChat);
164
165 return (id == d->mToMyGroup);
166 }
167
isToPlayerMessage(int id) const168 bool KGameChat::isToPlayerMessage(int id) const
169 {
170 Q_D(const KGameChat);
171
172 return d->mSendId2PlayerId.contains(id);
173 }
174
sendToPlayerEntry(const QString & name) const175 QString KGameChat::sendToPlayerEntry(const QString& name) const
176 {
177 return i18n("Send to %1", name);
178 }
179
playerId(int id) const180 int KGameChat::playerId(int id) const
181 {
182 Q_D(const KGameChat);
183
184 if (!isToPlayerMessage(id)) {
185 return -1;
186 }
187
188 return d->mSendId2PlayerId[id];
189 }
190
sendingId(int playerId) const191 int KGameChat::sendingId(int playerId) const
192 {
193 Q_D(const KGameChat);
194
195 QMap<int, int>::ConstIterator it;
196 for (it = d->mSendId2PlayerId.begin(); it != d->mSendId2PlayerId.end(); ++it) {
197 if (it.value() == playerId) {
198 return it.key();
199 }
200 }
201 return -1;
202 }
203
fromName() const204 QString KGameChat::fromName() const
205 {
206 Q_D(const KGameChat);
207
208 return d->mFromPlayer ? d->mFromPlayer->name() : QString();
209 }
210
hasPlayer(int id) const211 bool KGameChat::hasPlayer(int id) const
212 {
213 return (sendingId(id) != -1);
214 }
215
setFromPlayer(KPlayer * p)216 void KGameChat::setFromPlayer(KPlayer* p)
217 {
218 Q_D(KGameChat);
219
220 if (!p) {
221 qCCritical(GAMES_PRIVATE_KGAME) << ": NULL player";
222 removeSendingEntry(d->mToMyGroup);
223 d->mFromPlayer = nullptr;
224 return;
225 }
226 if (d->mFromPlayer) {
227 changeSendingEntry(p->group(), d->mToMyGroup);
228 } else {
229 if (d->mToMyGroup != -1) {
230 qCWarning(GAMES_PRIVATE_KGAME) << "send to my group exists already - removing";
231 removeSendingEntry(d->mToMyGroup);
232 }
233 d->mToMyGroup = nextId();
234 addSendingEntry(i18n("Send to My Group (\"%1\")", p->group()), d->mToMyGroup);
235 }
236 d->mFromPlayer = p;
237 qCDebug(GAMES_PRIVATE_KGAME) << "player=" << p;
238 }
239
240
setKGame(KGame * g)241 void KGameChat::setKGame(KGame* g)
242 {
243 Q_D(KGameChat);
244
245 if (d->mGame) {
246 slotUnsetKGame();
247 }
248 qCDebug(GAMES_PRIVATE_KGAME) << "game=" << g;
249 d->mGame = g;
250
251 if (d->mGame) {
252 connect(d->mGame, &KGame::signalPlayerJoinedGame, this, &KGameChat::slotAddPlayer);
253 connect(d->mGame, &KGame::signalPlayerLeftGame, this, &KGameChat::slotRemovePlayer);
254 connect(d->mGame, &KGame::signalNetworkData, this, &KGameChat::slotReceiveMessage);
255 connect(d->mGame, &KGame::destroyed, this, &KGameChat::slotUnsetKGame);
256
257 QList<KPlayer*> playerList = *d->mGame->playerList();
258 for (int i = 0; i < playerList.count(); i++) {
259 slotAddPlayer(playerList.at(i));
260 }
261 }
262 }
263
game() const264 KGame* KGameChat::game() const
265 {
266 Q_D(const KGameChat);
267
268 return d->mGame;
269 }
270
fromPlayer() const271 KPlayer* KGameChat::fromPlayer() const
272 {
273 Q_D(const KGameChat);
274
275 return d->mFromPlayer;
276 }
277
slotUnsetKGame()278 void KGameChat::slotUnsetKGame()
279 {
280 //TODO: test this method!
281 Q_D(KGameChat);
282
283 if (!d->mGame) {
284 return;
285 }
286 disconnect(d->mGame, nullptr, this, nullptr);
287 removeSendingEntry(d->mToMyGroup);
288 QMap<int, int>::Iterator it;
289 for (it = d->mSendId2PlayerId.begin(); it != d->mSendId2PlayerId.end(); ++it) {
290 removeSendingEntry(it.value());
291 }
292 }
293
slotAddPlayer(KPlayer * p)294 void KGameChat::slotAddPlayer(KPlayer* p)
295 {
296 Q_D(KGameChat);
297
298 if (!p) {
299 qCCritical(GAMES_PRIVATE_KGAME) << ": cannot add NULL player";
300 return;
301 }
302 if (hasPlayer(p->id())) {
303 qCCritical(GAMES_PRIVATE_KGAME) << ": player was added before";
304 return;
305 }
306
307 int sendingId = nextId();
308 addSendingEntry(comboBoxItem(p->name()), sendingId);
309 d->mSendId2PlayerId.insert(sendingId, p->id());
310 connect(p, &KPlayer::signalPropertyChanged, this, &KGameChat::slotPropertyChanged);
311 connect(p, &KPlayer::signalNetworkData, this, &KGameChat::slotReceivePrivateMessage);
312 }
313
slotRemovePlayer(KPlayer * p)314 void KGameChat::slotRemovePlayer(KPlayer* p)
315 {
316 Q_D(KGameChat);
317
318 if (!p) {
319 qCCritical(GAMES_PRIVATE_KGAME) << ": NULL player";
320 return;
321 }
322 if (!hasPlayer(p->id())) {
323 qCCritical(GAMES_PRIVATE_KGAME) << ": cannot remove non-existent player";
324 return;
325 }
326
327 int id = sendingId(p->id());
328 removeSendingEntry(id);
329 p->disconnect(this);
330 d->mSendId2PlayerId.remove(id);
331 }
332
slotPropertyChanged(KGamePropertyBase * prop,KPlayer * player)333 void KGameChat::slotPropertyChanged(KGamePropertyBase* prop, KPlayer* player)
334 {
335 if (prop->id() == KGamePropertyBase::IdName) {
336 // qCDebug(GAMES_PRIVATE_KGAME) << "new Name";
337 changeSendingEntry(player->name(), sendingId(player->id()));
338 /*
339 mCombo->changeItem(comboBoxItem(player->name()), index);
340 */
341 } else if (prop->id() == KGamePropertyBase::IdGroup) {
342 //TODO
343 }
344 }
345
slotReceivePrivateMessage(int msgid,const QByteArray & buffer,quint32 sender,KPlayer * me)346 void KGameChat::slotReceivePrivateMessage(int msgid, const QByteArray& buffer, quint32 sender, KPlayer* me)
347 {
348 if (!me || me != fromPlayer()) {
349 qCDebug(GAMES_PRIVATE_KGAME) << "nope - not for us!";
350 return;
351 }
352 slotReceiveMessage(msgid, buffer, me->id(), sender);
353 }
354
slotReceiveMessage(int msgid,const QByteArray & buffer,quint32,quint32 sender)355 void KGameChat::slotReceiveMessage(int msgid, const QByteArray& buffer, quint32 , quint32 sender)
356 {
357 QDataStream msg(buffer);
358 if (msgid != messageId()) {
359 return;
360 }
361
362 QString text;
363 msg >> text;
364
365 addMessage(sender, text);
366 }
367
368