fr.quatrevieux.araknemu.game.account.AccountService   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 125
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 49
dl 0
loc 125
ccs 37
cts 37
cp 1
rs 10
c 0
b 0
f 0
wmc 14

11 Methods

Rating   Name   Duplication   Size   Complexity  
$Listener$.on(PlayerLoaded) 0 3 ?
A listeners() 0 13 3
A AccountService(AccountRepository,GameConfiguration) 0 3 1
A logout(GameAccount) 0 2 1
$Listener$.event() 0 3 ?
A instantiate(Account) 0 2 1
A findByPseudo(String) 0 12 2
A login(GameAccount) 0 2 1
A load(Account) 0 2 1
A isLogged(int) 0 4 1
A getByIds(int[]) 0 21 3
1
/*
2
 * This file is part of Araknemu.
3
 *
4
 * Araknemu is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * Araknemu is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with Araknemu.  If not, see <https://www.gnu.org/licenses/>.
16
 *
17
 * Copyright (c) 2017-2020 Vincent Quatrevieux
18
 */
19
20
package fr.quatrevieux.araknemu.game.account;
21
22
import fr.quatrevieux.araknemu.core.event.EventsSubscriber;
23
import fr.quatrevieux.araknemu.core.event.Listener;
24
import fr.quatrevieux.araknemu.data.living.entity.account.Account;
25
import fr.quatrevieux.araknemu.data.living.repository.account.AccountRepository;
26
import fr.quatrevieux.araknemu.game.GameConfiguration;
27
import fr.quatrevieux.araknemu.game.listener.KickBannedAccount;
28
import fr.quatrevieux.araknemu.game.listener.account.SendAdminAccess;
29
import fr.quatrevieux.araknemu.game.player.event.PlayerLoaded;
30
31
import java.util.Arrays;
32
import java.util.HashMap;
33
import java.util.Map;
34
import java.util.Optional;
35
import java.util.concurrent.ConcurrentHashMap;
36
import java.util.concurrent.ConcurrentMap;
37
38
/**
39
 * Service for game accounts
40
 */
41
public final class AccountService implements EventsSubscriber {
42
    private final AccountRepository repository;
43
    private final GameConfiguration configuration;
44
45
    /**
46
     * Accounts indexed by race
47
     */
48 1
    private final ConcurrentMap<Integer, GameAccount> accounts = new ConcurrentHashMap<>();
49
50 1
    public AccountService(AccountRepository repository, GameConfiguration configuration) {
51 1
        this.repository = repository;
52 1
        this.configuration = configuration;
53 1
    }
54
55
    /**
56
     * Load an account
57
     *
58
     * @param account Account to load
59
     *
60
     * @throws fr.quatrevieux.araknemu.core.dbal.repository.EntityNotFoundException When cannot found the account
61
     */
62
    public GameAccount load(Account account) {
63 1
        return instantiate(repository.get(account));
64
    }
65
66
    /**
67
     * Check if the account is logged to the game server
68
     * @param accountId Account race
69
     */
70
    public boolean isLogged(int accountId) {
71 1
        final GameAccount account = accounts.get(accountId);
72
73 1
        return account != null && account.isLogged();
74
    }
75
76
    /**
77
     * Get multiple accounts by there ids
78
     * If an account is already logged, the logged account will be returned
79
     *
80
     * @param ids List of account ids
81
     *
82
     * @return The loaded accounts, indexed by account id
83
     */
84
    public Map<Integer, GameAccount> getByIds(int[] ids) {
85 1
        final Map<Integer, GameAccount> loadedAccounts = new HashMap<>();
86 1
        final int[] toLoad = Arrays.stream(ids)
87 1
            .filter(id -> {
88 1
                final GameAccount account = accounts.get(id);
89
90 1
                if (account != null) {
91 1
                    loadedAccounts.put(id, account);
92 1
                    return false;
93
                }
94
95 1
                return true;
96
            })
97 1
            .toArray()
98
        ;
99
100 1
        for (Account account : repository.findByIds(toLoad)) {
101 1
            loadedAccounts.put(account.id(), instantiate(account));
102 1
        }
103
104 1
        return loadedAccounts;
105
    }
106
107
    /**
108
     * Find an account by its pseudo
109
     * If the account is logged, the logged account is returned
110
     *
111
     * @param pseudo The pseudo to search
112
     *
113
     * @return The account. If the pseudo cannot be found, an empty optional is returned
114
     */
115
    public Optional<GameAccount> findByPseudo(String pseudo) {
116
        // @todo need index ? actually only used by admin command
0 ignored issues
show
introduced by
Comment matches to-do format '(TODO:)|(@todo )'.
Loading history...
117 1
        final Optional<GameAccount> loggedAccount = accounts.values().stream()
118 1
            .filter(gameAccount -> gameAccount.pseudo().equalsIgnoreCase(pseudo))
119 1
            .findFirst()
120
        ;
121
122 1
        if (loggedAccount.isPresent()) {
123 1
            return loggedAccount;
124
        }
125
126 1
        return repository.findByPseudo(pseudo).map(this::instantiate);
127
    }
128
129
    @Override
130
    public Listener[] listeners() {
131 1
        return new Listener[] {
132
            new KickBannedAccount(),
133 1
            new Listener<PlayerLoaded>() {
134
                @Override
135
                public void on(PlayerLoaded event) {
136 1
                    event.player().dispatcher().add(new SendAdminAccess());
137 1
                }
138
139
                @Override
140
                public Class<PlayerLoaded> event() {
141 1
                    return PlayerLoaded.class;
142
                }
143
            },
144
        };
145
    }
146
147
    /**
148
     * Set to logged accounts list
149
     */
150
    void login(GameAccount account) {
151 1
        accounts.put(account.id(), account);
152 1
    }
153
154
    /**
155
     * Remove from logged accounts list
156
     */
157
    void logout(GameAccount account) {
158 1
        accounts.remove(account.id());
159 1
    }
160
161
    /**
162
     * Instantiate the GameAccount for the given account entity
163
     */
164
    private GameAccount instantiate(Account entity) {
165 1
        return new GameAccount(entity, this, configuration.id());
166
    }
167
}
168