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
7
* This file is part of The ManaPlus Client.
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
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.
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/>.
23
#include "being/playerrelations.h"
25
#include "actorspritemanager.h"
26
#include "configuration.h"
28
#include "being/localplayer.h"
30
#include "utils/dtor.h"
31
#include "utils/gettext.h"
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;
42
static const char *const NAME = "name";
43
static const char *const RELATION = "relation";
45
static const unsigned int IGNORE_EMOTE_TIME = 100;
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;
52
class SortPlayersFunctor final
55
bool operator() (const std::string &str1,
56
const std::string &str2) const
58
std::string s1 = str1;
59
std::string s2 = str2;
68
// (De)serialisation class
69
class PlayerConfSerialiser final :
70
public ConfigurationListManager<std::pair<std::string, PlayerRelation *>,
71
std::map<std::string, PlayerRelation *> *>
74
virtual ConfigurationObject *writeConfigItem(
75
const std::pair<std::string, PlayerRelation *> &value,
76
ConfigurationObject *const cobj) const override
78
if (!cobj || !value.second)
80
cobj->setValue(NAME, value.first);
81
cobj->setValue(RELATION, toString(
82
static_cast<int>(value.second->mRelation)));
87
virtual std::map<std::string, PlayerRelation *> *
88
readConfigItem(const ConfigurationObject *const cobj,
89
std::map<std::string, PlayerRelation *>
90
*const container) const override
94
const std::string name = cobj->getValue(NAME, "");
98
if (!(*container)[name])
100
const int v = cobj->getValueInt(RELATION,
101
static_cast<int>(PlayerRelation::NEUTRAL));
103
(*container)[name] = new PlayerRelation(
104
static_cast<PlayerRelation::Relation>(v));
106
// otherwise ignore the duplicate entry
112
static PlayerConfSerialiser player_conf_serialiser; // stateless singleton
114
const unsigned int PlayerRelation::RELATION_PERMISSIONS[RELATIONS_NR] =
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,
120
/* ERASED */ INVISIBLE,
121
/* BLACKLISTED */ SPEECH_LOG | WHISPER,
122
/* ENEMY2 */ EMOTE | SPEECH_FLOAT | SPEECH_LOG | WHISPER | TRADE
125
PlayerRelation::PlayerRelation(const Relation relation) :
130
PlayerRelationsManager::PlayerRelationsManager() :
131
mPersistIgnores(false),
132
mDefaultPermissions(PlayerRelation::DEFAULT),
133
mIgnoreStrategy(nullptr),
140
PlayerRelationsManager::~PlayerRelationsManager()
142
delete_all(mIgnoreStrategies);
144
FOR_EACH (PlayerRelationsCIter, it, mRelations)
149
void PlayerRelationsManager::clear()
151
StringVect *const names = getPlayers();
152
FOR_EACHP (StringVectCIter, it, names)
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";
161
int PlayerRelationsManager::getPlayerIgnoreStrategyIndex(
162
const std::string &name)
164
const std::vector<PlayerIgnoreStrategy *> *const strategies
165
= getPlayerIgnoreStrategies();
170
const size_t sz = strategies->size();
171
for (size_t i = 0; i < sz; i++)
173
if ((*strategies)[i]->mShortName == name)
180
void PlayerRelationsManager::load(const bool oldConfig)
189
mPersistIgnores = cfg->getValue(PERSIST_IGNORE_LIST, 1);
190
mDefaultPermissions = static_cast<int>(cfg->getValue(DEFAULT_PERMISSIONS,
191
mDefaultPermissions));
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);
198
if (ignore_strategy_index >= 0)
200
setPlayerIgnoreStrategy((*getPlayerIgnoreStrategies())
201
[ignore_strategy_index]);
204
cfg->getList<std::pair<std::string, PlayerRelation *>,
205
std::map<std::string, PlayerRelation *> *>
206
("player", &(mRelations), &player_conf_serialiser);
210
void PlayerRelationsManager::init()
214
if (!mPersistIgnores)
216
clear(); // Yes, we still keep them around in the config file
217
// until the next update.
220
FOR_EACH (PlayerRelationListenersCIter, it, mListeners)
224
void PlayerRelationsManager::store() const
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);
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);
239
serverConfig.write();
242
void PlayerRelationsManager::signalUpdate(const std::string &name)
244
FOR_EACH (PlayerRelationListenersCIter, it, mListeners)
245
(*it)->updatedPlayer(name);
247
if (actorSpriteManager)
249
Being *const being = actorSpriteManager->findBeingByName(
250
name, Being::PLAYER);
252
if (being && being->getType() == Being::PLAYER)
253
being->updateColors();
257
unsigned int PlayerRelationsManager::checkPermissionSilently(
258
const std::string &player_name, const unsigned int flags) const
260
const std::map<std::string, PlayerRelation *>::const_iterator
261
it = mRelations.find(player_name);
262
if (it == mRelations.end())
264
return mDefaultPermissions & flags;
268
const PlayerRelation *const r = (*it).second;
269
unsigned int permissions =
270
PlayerRelation::RELATION_PERMISSIONS[r->mRelation];
272
switch (r->mRelation)
274
case PlayerRelation::NEUTRAL:
275
permissions = mDefaultPermissions;
278
case PlayerRelation::FRIEND:
279
permissions |= mDefaultPermissions; // widen
282
case PlayerRelation::DISREGARDED:
283
case PlayerRelation::IGNORED:
284
case PlayerRelation::ERASED:
285
case PlayerRelation::BLACKLISTED:
286
case PlayerRelation::ENEMY2:
288
permissions &= mDefaultPermissions; // narrow
291
return permissions & flags;
295
bool PlayerRelationsManager::hasPermission(const Being *const being,
296
const unsigned int flags) const
301
if (being->getType() == ActorSprite::PLAYER)
302
return hasPermission(being->getName(), flags) == flags;
306
bool PlayerRelationsManager::hasPermission(const std::string &name,
307
const unsigned int flags) const
309
if (!actorSpriteManager)
312
const unsigned int rejections = flags
313
& ~checkPermissionSilently(name, flags);
314
const bool permitted = (rejections == 0);
318
// execute `ignore' strategy, if possible
321
Being *const b = actorSpriteManager->findBeingByName(
322
name, ActorSprite::PLAYER);
324
if (b && b->getType() == ActorSprite::PLAYER)
325
mIgnoreStrategy->ignore(b, rejections);
332
void PlayerRelationsManager::setRelation(const std::string &player_name,
333
const PlayerRelation::Relation
336
if (!player_node || (relation != PlayerRelation::NEUTRAL
337
&& player_node->getName() == player_name))
342
PlayerRelation *const r = mRelations[player_name];
344
mRelations[player_name] = new PlayerRelation(relation);
346
r->mRelation = relation;
348
signalUpdate(player_name);
351
StringVect *PlayerRelationsManager::getPlayers() const
353
StringVect *const retval = new StringVect();
355
FOR_EACH (PlayerRelationsCIter, it, mRelations)
358
retval->push_back(it->first);
361
std::sort(retval->begin(), retval->end(), playersRelSorter);
366
StringVect *PlayerRelationsManager::getPlayersByRelation(
367
const PlayerRelation::Relation rel) const
369
StringVect *const retval = new StringVect();
371
FOR_EACH (PlayerRelationsCIter, it, mRelations)
373
if (it->second && it->second->mRelation == rel)
374
retval->push_back(it->first);
377
std::sort(retval->begin(), retval->end(), playersRelSorter);
382
void PlayerRelationsManager::removePlayer(const std::string &name)
384
delete mRelations[name];
385
mRelations.erase(name);
390
PlayerRelation::Relation PlayerRelationsManager::getRelation(
391
const std::string &name) const
393
const std::map<std::string, PlayerRelation *>::const_iterator
394
it = mRelations.find(name);
395
if (it != mRelations.end())
396
return (*it).second->mRelation;
398
return PlayerRelation::NEUTRAL;
401
////////////////////////////////////////
404
unsigned int PlayerRelationsManager::getDefault() const
406
return mDefaultPermissions;
409
void PlayerRelationsManager::setDefault(const unsigned int permissions)
411
mDefaultPermissions = permissions;
417
void PlayerRelationsManager::ignoreTrade(const std::string &name)
422
const PlayerRelation::Relation relation = getRelation(name);
424
if (relation == PlayerRelation::IGNORED
425
|| relation == PlayerRelation::DISREGARDED
426
|| relation == PlayerRelation::BLACKLISTED
427
|| relation == PlayerRelation::ERASED)
433
player_relations.setRelation(name, PlayerRelation::BLACKLISTED);
437
bool PlayerRelationsManager::checkBadRelation(const std::string &name) const
442
const PlayerRelation::Relation relation = getRelation(name);
444
if (relation == PlayerRelation::IGNORED
445
|| relation == PlayerRelation::DISREGARDED
446
|| relation == PlayerRelation::BLACKLISTED
447
|| relation == PlayerRelation::ERASED
448
|| relation == PlayerRelation::ENEMY2)
455
////////////////////////////////////////
459
class PIS_nothing final : public PlayerIgnoreStrategy
463
PlayerIgnoreStrategy()
465
// TRANSLATORS: ignore/unignore action
466
mDescription = _("Completely ignore");
467
mShortName = PLAYER_IGNORE_STRATEGY_NOP;
470
virtual void ignore(Being *const being A_UNUSED,
471
const unsigned int flags A_UNUSED) const override
476
class PIS_dotdotdot final : public PlayerIgnoreStrategy
480
PlayerIgnoreStrategy()
482
// TRANSLATORS: ignore/unignore action
483
mDescription = _("Print '...'");
484
mShortName = "dotdotdot";
487
virtual void ignore(Being *const being,
488
const unsigned int flags A_UNUSED) const override
493
logger->log("ignoring: " + being->getName());
494
being->setSpeech("...");
499
class PIS_blinkname final : public PlayerIgnoreStrategy
503
PlayerIgnoreStrategy()
505
// TRANSLATORS: ignore/unignore action
506
mDescription = _("Blink name");
507
mShortName = "blinkname";
510
virtual void ignore(Being *const being,
511
const unsigned int flags A_UNUSED) const override
516
logger->log("ignoring: " + being->getName());
517
being->flashName(200);
521
class PIS_emote final : public PlayerIgnoreStrategy
524
PIS_emote(const uint8_t emote_nr, const std::string &description,
525
const std::string &shortname) :
526
PlayerIgnoreStrategy(),
529
mDescription = description;
530
mShortName = shortname;
533
virtual void ignore(Being *const being,
534
const unsigned int flags A_UNUSED) const override
539
being->setEmote(mEmotion, IGNORE_EMOTE_TIME);
544
std::vector<PlayerIgnoreStrategy *> *
545
PlayerRelationsManager::getPlayerIgnoreStrategies()
547
if (mIgnoreStrategies.empty())
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"),
558
mIgnoreStrategies.push_back(new PIS_nothing);
559
mIgnoreStrategies.push_back(new PIS_dotdotdot);
560
mIgnoreStrategies.push_back(new PIS_blinkname);
562
return &mIgnoreStrategies;
565
bool PlayerRelationsManager::isGoodName(const std::string &name) const
567
const size_t size = name.size();
572
const std::map<std::string, PlayerRelation *>::const_iterator
573
it = mRelations.find(name);
574
if (it != mRelations.end())
577
return checkName(name);
580
bool PlayerRelationsManager::isGoodName(Being *const being) const
584
if (being->getGoodStatus() != -1)
585
return (being->getGoodStatus() == 1);
587
const std::string name = being->getName();
588
const size_t size = name.size();
593
const std::map<std::string, PlayerRelation *>::const_iterator
594
it = mRelations.find(name);
595
if (it != mRelations.end())
598
const bool status = checkName(name);
599
being->setGoodStatus(status ? 1 : 0);
603
bool PlayerRelationsManager::checkName(const std::string &name) const
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);
609
if (name.substr(0, 1) == " " || lastChar == " " || lastChar == "."
610
|| name.find(" ") != std::string::npos)
614
else if (check.empty())
618
else if (name.find_first_of(check) != std::string::npos)
628
PlayerRelationsManager player_relations;