~ubuntu-branches/ubuntu/trusty/manaplus/trusty-proposed

« back to all changes in this revision

Viewing changes to src/being/playerrelations.cpp

  • Committer: Package Import Robot
  • Author(s): Patrick Matthäi
  • Date: 2013-09-17 10:35:51 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20130917103551-az7p3nz9jgxwqjfn
Tags: 1.3.9.15-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  The ManaPlus Client
 
3
 *  Copyright (C) 2008-2009  The Mana World Development Team
 
4
 *  Copyright (C) 2009-2010  The Mana Developers
 
5
 *  Copyright (C) 2011-2013  The ManaPlus Developers
 
6
 *
 
7
 *  This file is part of The ManaPlus Client.
 
8
 *
 
9
 *  This program is free software; you can redistribute it and/or modify
 
10
 *  it under the terms of the GNU General Public License as published by
 
11
 *  the Free Software Foundation; either version 2 of the License, or
 
12
 *  any later version.
 
13
 *
 
14
 *  This program is distributed in the hope that it will be useful,
 
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 *  GNU General Public License for more details.
 
18
 *
 
19
 *  You should have received a copy of the GNU General Public License
 
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
 */
 
22
 
 
23
#include "being/playerrelations.h"
 
24
 
 
25
#include "actorspritemanager.h"
 
26
#include "configuration.h"
 
27
 
 
28
#include "being/localplayer.h"
 
29
 
 
30
#include "utils/dtor.h"
 
31
#include "utils/gettext.h"
 
32
 
 
33
#include <algorithm>
 
34
 
 
35
#include "debug.h"
 
36
 
 
37
static const char *const PLAYER_IGNORE_STRATEGY_NOP = "nop";
 
38
static const char *const PLAYER_IGNORE_STRATEGY_EMOTE0 = "emote0";
 
39
static const char *const DEFAULT_IGNORE_STRATEGY
 
40
    = PLAYER_IGNORE_STRATEGY_EMOTE0;
 
41
 
 
42
static const char *const NAME = "name";
 
43
static const char *const RELATION = "relation";
 
44
 
 
45
static const unsigned int IGNORE_EMOTE_TIME = 100;
 
46
 
 
47
typedef std::map<std::string, PlayerRelation *> PlayerRelations;
 
48
typedef PlayerRelations::const_iterator PlayerRelationsCIter;
 
49
typedef std::list<PlayerRelationsListener *> PlayerRelationListeners;
 
50
typedef PlayerRelationListeners::const_iterator PlayerRelationListenersCIter;
 
51
 
 
52
class SortPlayersFunctor final
 
53
{
 
54
    public:
 
55
        bool operator() (const std::string &str1,
 
56
                         const std::string &str2) const
 
57
        {
 
58
            std::string s1 = str1;
 
59
            std::string s2 = str2;
 
60
            toLower(s1);
 
61
            toLower(s2);
 
62
            if (s1 == s2)
 
63
                return str1 < str2;
 
64
            return s1 < s2;
 
65
        }
 
66
} playersRelSorter;
 
67
 
 
68
// (De)serialisation class
 
69
class PlayerConfSerialiser final :
 
70
    public ConfigurationListManager<std::pair<std::string, PlayerRelation *>,
 
71
        std::map<std::string, PlayerRelation *> *>
 
72
{
 
73
public:
 
74
    virtual ConfigurationObject *writeConfigItem(
 
75
        const std::pair<std::string, PlayerRelation *> &value,
 
76
        ConfigurationObject *const cobj) const override
 
77
    {
 
78
        if (!cobj || !value.second)
 
79
            return nullptr;
 
80
        cobj->setValue(NAME, value.first);
 
81
        cobj->setValue(RELATION, toString(
 
82
                static_cast<int>(value.second->mRelation)));
 
83
 
 
84
        return cobj;
 
85
    }
 
86
 
 
87
    virtual std::map<std::string, PlayerRelation *> *
 
88
    readConfigItem(const ConfigurationObject *const cobj,
 
89
                   std::map<std::string, PlayerRelation *>
 
90
                   *const container) const override
 
91
    {
 
92
        if (!cobj)
 
93
            return container;
 
94
        const std::string name = cobj->getValue(NAME, "");
 
95
        if (name.empty())
 
96
            return container;
 
97
 
 
98
        if (!(*container)[name])
 
99
        {
 
100
            const int v = cobj->getValueInt(RELATION,
 
101
                static_cast<int>(PlayerRelation::NEUTRAL));
 
102
 
 
103
            (*container)[name] = new PlayerRelation(
 
104
                static_cast<PlayerRelation::Relation>(v));
 
105
        }
 
106
        // otherwise ignore the duplicate entry
 
107
 
 
108
        return container;
 
109
    }
 
110
};
 
111
 
 
112
static PlayerConfSerialiser player_conf_serialiser;  // stateless singleton
 
113
 
 
114
const unsigned int PlayerRelation::RELATION_PERMISSIONS[RELATIONS_NR] =
 
115
{
 
116
    /* NEUTRAL */     0,  // we always fall back to the defaults anyway
 
117
    /* FRIEND  */     EMOTE | SPEECH_FLOAT | SPEECH_LOG | WHISPER | TRADE,
 
118
    /* DISREGARDED*/  EMOTE | SPEECH_FLOAT,
 
119
    /* IGNORED */     0,
 
120
    /* ERASED */      INVISIBLE,
 
121
    /* BLACKLISTED */ SPEECH_LOG | WHISPER,
 
122
    /* ENEMY2 */      EMOTE | SPEECH_FLOAT | SPEECH_LOG | WHISPER | TRADE
 
123
};
 
124
 
 
125
PlayerRelation::PlayerRelation(const Relation relation) :
 
126
    mRelation(relation)
 
127
{
 
128
}
 
129
 
 
130
PlayerRelationsManager::PlayerRelationsManager() :
 
131
    mPersistIgnores(false),
 
132
    mDefaultPermissions(PlayerRelation::DEFAULT),
 
133
    mIgnoreStrategy(nullptr),
 
134
    mRelations(),
 
135
    mListeners(),
 
136
    mIgnoreStrategies()
 
137
{
 
138
}
 
139
 
 
140
PlayerRelationsManager::~PlayerRelationsManager()
 
141
{
 
142
    delete_all(mIgnoreStrategies);
 
143
 
 
144
    FOR_EACH (PlayerRelationsCIter, it, mRelations)
 
145
        delete it->second;
 
146
    mRelations.clear();
 
147
}
 
148
 
 
149
void PlayerRelationsManager::clear()
 
150
{
 
151
    StringVect *const names = getPlayers();
 
152
    FOR_EACHP (StringVectCIter, it, names)
 
153
        removePlayer(*it);
 
154
    delete names;
 
155
}
 
156
 
 
157
static const char *const PERSIST_IGNORE_LIST = "persistent-player-list";
 
158
static const char *const PLAYER_IGNORE_STRATEGY = "player-ignore-strategy";
 
159
static const char *const DEFAULT_PERMISSIONS = "default-player-permissions";
 
160
 
 
161
int PlayerRelationsManager::getPlayerIgnoreStrategyIndex(
 
162
    const std::string &name)
 
163
{
 
164
    const std::vector<PlayerIgnoreStrategy *> *const strategies
 
165
        = getPlayerIgnoreStrategies();
 
166
 
 
167
    if (!strategies)
 
168
        return -1;
 
169
 
 
170
    const size_t sz = strategies->size();
 
171
    for (size_t i = 0; i < sz; i++)
 
172
    {
 
173
        if ((*strategies)[i]->mShortName == name)
 
174
            return i;
 
175
    }
 
176
 
 
177
    return -1;
 
178
}
 
179
 
 
180
void PlayerRelationsManager::load(const bool oldConfig)
 
181
{
 
182
    Configuration *cfg;
 
183
    if (oldConfig)
 
184
        cfg = &config;
 
185
    else
 
186
        cfg = &serverConfig;
 
187
    clear();
 
188
 
 
189
    mPersistIgnores = cfg->getValue(PERSIST_IGNORE_LIST, 1);
 
190
    mDefaultPermissions = static_cast<int>(cfg->getValue(DEFAULT_PERMISSIONS,
 
191
                                           mDefaultPermissions));
 
192
 
 
193
    const std::string ignore_strategy_name = cfg->getValue(
 
194
        PLAYER_IGNORE_STRATEGY, DEFAULT_IGNORE_STRATEGY);
 
195
    const int ignore_strategy_index = getPlayerIgnoreStrategyIndex(
 
196
        ignore_strategy_name);
 
197
 
 
198
    if (ignore_strategy_index >= 0)
 
199
    {
 
200
        setPlayerIgnoreStrategy((*getPlayerIgnoreStrategies())
 
201
                                [ignore_strategy_index]);
 
202
    }
 
203
 
 
204
    cfg->getList<std::pair<std::string, PlayerRelation *>,
 
205
                   std::map<std::string, PlayerRelation *> *>
 
206
        ("player",  &(mRelations), &player_conf_serialiser);
 
207
}
 
208
 
 
209
 
 
210
void PlayerRelationsManager::init()
 
211
{
 
212
    load();
 
213
 
 
214
    if (!mPersistIgnores)
 
215
    {
 
216
        clear();  // Yes, we still keep them around in the config file
 
217
                  // until the next update.
 
218
    }
 
219
 
 
220
    FOR_EACH (PlayerRelationListenersCIter, it, mListeners)
 
221
        (*it)->updateAll();
 
222
}
 
223
 
 
224
void PlayerRelationsManager::store() const
 
225
{
 
226
    serverConfig.setList<std::map<std::string,
 
227
        PlayerRelation *>::const_iterator,
 
228
        std::pair<std::string, PlayerRelation *>,
 
229
        std::map<std::string, PlayerRelation *> *>
 
230
        ("player", mRelations.begin(), mRelations.end(),
 
231
        &player_conf_serialiser);
 
232
 
 
233
    serverConfig.setValue(DEFAULT_PERMISSIONS, mDefaultPermissions);
 
234
    serverConfig.setValue(PERSIST_IGNORE_LIST, mPersistIgnores);
 
235
    serverConfig.setValue(PLAYER_IGNORE_STRATEGY,
 
236
                          mIgnoreStrategy ? mIgnoreStrategy->mShortName
 
237
                          : DEFAULT_IGNORE_STRATEGY);
 
238
 
 
239
    serverConfig.write();
 
240
}
 
241
 
 
242
void PlayerRelationsManager::signalUpdate(const std::string &name)
 
243
{
 
244
    FOR_EACH (PlayerRelationListenersCIter, it, mListeners)
 
245
        (*it)->updatedPlayer(name);
 
246
 
 
247
    if (actorSpriteManager)
 
248
    {
 
249
        Being *const being = actorSpriteManager->findBeingByName(
 
250
            name, Being::PLAYER);
 
251
 
 
252
        if (being && being->getType() == Being::PLAYER)
 
253
            being->updateColors();
 
254
    }
 
255
}
 
256
 
 
257
unsigned int PlayerRelationsManager::checkPermissionSilently(
 
258
    const std::string &player_name, const unsigned int flags) const
 
259
{
 
260
    const std::map<std::string, PlayerRelation *>::const_iterator
 
261
        it = mRelations.find(player_name);
 
262
    if (it == mRelations.end())
 
263
    {
 
264
        return mDefaultPermissions & flags;
 
265
    }
 
266
    else
 
267
    {
 
268
        const PlayerRelation *const r = (*it).second;
 
269
        unsigned int permissions =
 
270
            PlayerRelation::RELATION_PERMISSIONS[r->mRelation];
 
271
 
 
272
        switch (r->mRelation)
 
273
        {
 
274
            case PlayerRelation::NEUTRAL:
 
275
                permissions = mDefaultPermissions;
 
276
                break;
 
277
 
 
278
            case PlayerRelation::FRIEND:
 
279
                permissions |= mDefaultPermissions;  // widen
 
280
                break;
 
281
 
 
282
            case PlayerRelation::DISREGARDED:
 
283
            case PlayerRelation::IGNORED:
 
284
            case PlayerRelation::ERASED:
 
285
            case PlayerRelation::BLACKLISTED:
 
286
            case PlayerRelation::ENEMY2:
 
287
            default:
 
288
                permissions &= mDefaultPermissions;  // narrow
 
289
        }
 
290
 
 
291
        return permissions & flags;
 
292
    }
 
293
}
 
294
 
 
295
bool PlayerRelationsManager::hasPermission(const Being *const being,
 
296
                                           const unsigned int flags) const
 
297
{
 
298
    if (!being)
 
299
        return false;
 
300
 
 
301
    if (being->getType() == ActorSprite::PLAYER)
 
302
        return hasPermission(being->getName(), flags) == flags;
 
303
    return true;
 
304
}
 
305
 
 
306
bool PlayerRelationsManager::hasPermission(const std::string &name,
 
307
                                           const unsigned int flags) const
 
308
{
 
309
    if (!actorSpriteManager)
 
310
        return false;
 
311
 
 
312
    const unsigned int rejections = flags
 
313
        & ~checkPermissionSilently(name, flags);
 
314
    const bool permitted = (rejections == 0);
 
315
 
 
316
    if (!permitted)
 
317
    {
 
318
        // execute `ignore' strategy, if possible
 
319
        if (mIgnoreStrategy)
 
320
        {
 
321
            Being *const b = actorSpriteManager->findBeingByName(
 
322
                name, ActorSprite::PLAYER);
 
323
 
 
324
            if (b && b->getType() == ActorSprite::PLAYER)
 
325
                mIgnoreStrategy->ignore(b, rejections);
 
326
        }
 
327
    }
 
328
 
 
329
    return permitted;
 
330
}
 
331
 
 
332
void PlayerRelationsManager::setRelation(const std::string &player_name,
 
333
                                         const PlayerRelation::Relation
 
334
                                         relation)
 
335
{
 
336
    if (!player_node || (relation != PlayerRelation::NEUTRAL
 
337
        && player_node->getName() == player_name))
 
338
    {
 
339
        return;
 
340
    }
 
341
 
 
342
    PlayerRelation *const r = mRelations[player_name];
 
343
    if (!r)
 
344
        mRelations[player_name] = new PlayerRelation(relation);
 
345
    else
 
346
        r->mRelation = relation;
 
347
 
 
348
    signalUpdate(player_name);
 
349
}
 
350
 
 
351
StringVect *PlayerRelationsManager::getPlayers() const
 
352
{
 
353
    StringVect *const retval = new StringVect();
 
354
 
 
355
    FOR_EACH (PlayerRelationsCIter, it, mRelations)
 
356
    {
 
357
        if (it->second)
 
358
            retval->push_back(it->first);
 
359
    }
 
360
 
 
361
    std::sort(retval->begin(), retval->end(), playersRelSorter);
 
362
 
 
363
    return retval;
 
364
}
 
365
 
 
366
StringVect *PlayerRelationsManager::getPlayersByRelation(
 
367
    const PlayerRelation::Relation rel) const
 
368
{
 
369
    StringVect *const retval = new StringVect();
 
370
 
 
371
    FOR_EACH (PlayerRelationsCIter, it, mRelations)
 
372
    {
 
373
        if (it->second && it->second->mRelation == rel)
 
374
            retval->push_back(it->first);
 
375
    }
 
376
 
 
377
    std::sort(retval->begin(), retval->end(), playersRelSorter);
 
378
 
 
379
    return retval;
 
380
}
 
381
 
 
382
void PlayerRelationsManager::removePlayer(const std::string &name)
 
383
{
 
384
    delete mRelations[name];
 
385
    mRelations.erase(name);
 
386
    signalUpdate(name);
 
387
}
 
388
 
 
389
 
 
390
PlayerRelation::Relation PlayerRelationsManager::getRelation(
 
391
    const std::string &name) const
 
392
{
 
393
    const std::map<std::string, PlayerRelation *>::const_iterator
 
394
        it = mRelations.find(name);
 
395
    if (it != mRelations.end())
 
396
        return (*it).second->mRelation;
 
397
 
 
398
    return PlayerRelation::NEUTRAL;
 
399
}
 
400
 
 
401
////////////////////////////////////////
 
402
// defaults
 
403
 
 
404
unsigned int PlayerRelationsManager::getDefault() const
 
405
{
 
406
    return mDefaultPermissions;
 
407
}
 
408
 
 
409
void PlayerRelationsManager::setDefault(const unsigned int permissions)
 
410
{
 
411
    mDefaultPermissions = permissions;
 
412
 
 
413
    store();
 
414
    signalUpdate("");
 
415
}
 
416
 
 
417
void PlayerRelationsManager::ignoreTrade(const std::string &name)
 
418
{
 
419
    if (name.empty())
 
420
        return;
 
421
 
 
422
    const PlayerRelation::Relation relation = getRelation(name);
 
423
 
 
424
    if (relation == PlayerRelation::IGNORED
 
425
        || relation == PlayerRelation::DISREGARDED
 
426
        || relation == PlayerRelation::BLACKLISTED
 
427
        || relation == PlayerRelation::ERASED)
 
428
    {
 
429
        return;
 
430
    }
 
431
    else
 
432
    {
 
433
        player_relations.setRelation(name, PlayerRelation::BLACKLISTED);
 
434
    }
 
435
}
 
436
 
 
437
bool PlayerRelationsManager::checkBadRelation(const std::string &name) const
 
438
{
 
439
    if (name.empty())
 
440
        return true;
 
441
 
 
442
    const PlayerRelation::Relation relation = getRelation(name);
 
443
 
 
444
    if (relation == PlayerRelation::IGNORED
 
445
        || relation == PlayerRelation::DISREGARDED
 
446
        || relation == PlayerRelation::BLACKLISTED
 
447
        || relation == PlayerRelation::ERASED
 
448
        || relation == PlayerRelation::ENEMY2)
 
449
    {
 
450
        return true;
 
451
    }
 
452
    return false;
 
453
}
 
454
 
 
455
////////////////////////////////////////
 
456
// ignore strategies
 
457
 
 
458
 
 
459
class PIS_nothing final : public PlayerIgnoreStrategy
 
460
{
 
461
public:
 
462
    PIS_nothing() :
 
463
        PlayerIgnoreStrategy()
 
464
    {
 
465
        // TRANSLATORS: ignore/unignore action
 
466
        mDescription = _("Completely ignore");
 
467
        mShortName = PLAYER_IGNORE_STRATEGY_NOP;
 
468
    }
 
469
 
 
470
    virtual void ignore(Being *const being A_UNUSED,
 
471
                        const unsigned int flags A_UNUSED) const override
 
472
    {
 
473
    }
 
474
};
 
475
 
 
476
class PIS_dotdotdot final : public PlayerIgnoreStrategy
 
477
{
 
478
public:
 
479
    PIS_dotdotdot() :
 
480
        PlayerIgnoreStrategy()
 
481
    {
 
482
        // TRANSLATORS: ignore/unignore action
 
483
        mDescription = _("Print '...'");
 
484
        mShortName = "dotdotdot";
 
485
    }
 
486
 
 
487
    virtual void ignore(Being *const being,
 
488
                        const unsigned int flags A_UNUSED) const override
 
489
    {
 
490
        if (!being)
 
491
            return;
 
492
 
 
493
        logger->log("ignoring: " + being->getName());
 
494
        being->setSpeech("...");
 
495
    }
 
496
};
 
497
 
 
498
 
 
499
class PIS_blinkname final : public PlayerIgnoreStrategy
 
500
{
 
501
public:
 
502
    PIS_blinkname() :
 
503
        PlayerIgnoreStrategy()
 
504
    {
 
505
        // TRANSLATORS: ignore/unignore action
 
506
        mDescription = _("Blink name");
 
507
        mShortName = "blinkname";
 
508
    }
 
509
 
 
510
    virtual void ignore(Being *const being,
 
511
                        const unsigned int flags A_UNUSED) const override
 
512
    {
 
513
        if (!being)
 
514
            return;
 
515
 
 
516
        logger->log("ignoring: " + being->getName());
 
517
        being->flashName(200);
 
518
    }
 
519
};
 
520
 
 
521
class PIS_emote final : public PlayerIgnoreStrategy
 
522
{
 
523
public:
 
524
    PIS_emote(const uint8_t emote_nr, const std::string &description,
 
525
              const std::string &shortname) :
 
526
        PlayerIgnoreStrategy(),
 
527
        mEmotion(emote_nr)
 
528
    {
 
529
        mDescription = description;
 
530
        mShortName = shortname;
 
531
    }
 
532
 
 
533
    virtual void ignore(Being *const being,
 
534
                        const unsigned int flags A_UNUSED) const override
 
535
    {
 
536
        if (!being)
 
537
            return;
 
538
 
 
539
        being->setEmote(mEmotion, IGNORE_EMOTE_TIME);
 
540
    }
 
541
    uint8_t mEmotion;
 
542
};
 
543
 
 
544
std::vector<PlayerIgnoreStrategy *> *
 
545
PlayerRelationsManager::getPlayerIgnoreStrategies()
 
546
{
 
547
    if (mIgnoreStrategies.empty())
 
548
    {
 
549
        // not initialised yet?
 
550
        mIgnoreStrategies.push_back(new PIS_emote(FIRST_IGNORE_EMOTE,
 
551
                                    // TRANSLATORS: ignore strategi
 
552
                                    _("Floating '...' bubble"),
 
553
                                    PLAYER_IGNORE_STRATEGY_EMOTE0));
 
554
        mIgnoreStrategies.push_back(new PIS_emote(FIRST_IGNORE_EMOTE + 1,
 
555
                                    // TRANSLATORS: ignore strategi
 
556
                                    _("Floating bubble"),
 
557
                                    "emote1"));
 
558
        mIgnoreStrategies.push_back(new PIS_nothing);
 
559
        mIgnoreStrategies.push_back(new PIS_dotdotdot);
 
560
        mIgnoreStrategies.push_back(new PIS_blinkname);
 
561
    }
 
562
    return &mIgnoreStrategies;
 
563
}
 
564
 
 
565
bool PlayerRelationsManager::isGoodName(const std::string &name) const
 
566
{
 
567
    const size_t size = name.size();
 
568
 
 
569
    if (size < 3)
 
570
        return true;
 
571
 
 
572
    const std::map<std::string, PlayerRelation *>::const_iterator
 
573
        it = mRelations.find(name);
 
574
    if (it != mRelations.end())
 
575
        return true;
 
576
 
 
577
    return checkName(name);
 
578
}
 
579
 
 
580
bool PlayerRelationsManager::isGoodName(Being *const being) const
 
581
{
 
582
    if (!being)
 
583
        return false;
 
584
    if (being->getGoodStatus() != -1)
 
585
        return (being->getGoodStatus() == 1);
 
586
 
 
587
    const std::string name = being->getName();
 
588
    const size_t size = name.size();
 
589
 
 
590
    if (size < 3)
 
591
        return true;
 
592
 
 
593
    const std::map<std::string, PlayerRelation *>::const_iterator
 
594
        it = mRelations.find(name);
 
595
    if (it != mRelations.end())
 
596
        return true;
 
597
 
 
598
    const bool status = checkName(name);
 
599
    being->setGoodStatus(status ? 1 : 0);
 
600
    return status;
 
601
}
 
602
 
 
603
bool PlayerRelationsManager::checkName(const std::string &name) const
 
604
{
 
605
    const size_t size = name.size();
 
606
    const std::string check = config.getStringValue("unsecureChars");
 
607
    const std::string lastChar = name.substr(size - 1, 1);
 
608
 
 
609
    if (name.substr(0, 1) == " " || lastChar == " " || lastChar == "."
 
610
        || name.find("  ") != std::string::npos)
 
611
    {
 
612
        return false;
 
613
    }
 
614
    else if (check.empty())
 
615
    {
 
616
        return true;
 
617
    }
 
618
    else if (name.find_first_of(check) != std::string::npos)
 
619
    {
 
620
        return false;
 
621
    }
 
622
    else
 
623
    {
 
624
        return true;
 
625
    }
 
626
}
 
627
 
 
628
PlayerRelationsManager player_relations;