-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPlayerMarket.cpp
More file actions
332 lines (307 loc) · 10.4 KB
/
Copy pathPlayerMarket.cpp
File metadata and controls
332 lines (307 loc) · 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#include "PlayerMarket.hpp"
#include <Constants.hpp>
#include <sys/stat.h>
#include <stdio.h>
#include <Exception.hpp>
#include <model/MemoryAccess.hpp>
#include <math.h>
#include <model/Gear.hpp>
#include <model/RandomNameGenerator.hpp>
#include <utility>
/// Constructor
PlayerMarket::PlayerMarket(const ServerManager & parent): ServerManager(parent), _sales(), _locker(PTHREAD_MUTEX_INITIALIZER) {
MemoryAccess::load(_sales);
}
/// Destructor
PlayerMarket::~PlayerMarket(){
for(size_t i=0;i<_sales.size();++i){
delete _sales[i];
}
}
/**
* Method creating a sale
* @param int : id of the player to be put on sale
* @param int : value of the player to be put on sale
* @param Player : player to be put on sale
* @param std::string : user whose player will be put on sales
*/
void PlayerMarket::createSale(int player_id, int value, Player& player, std::string username){
if(pthread_mutex_lock(&_locker) != 0)
throw "Couldn't acquire lock for PlayerMarket";
_sales.push_back(new Sale(value, username, player_id, player));
Sale *added = getSale(player_id);
added->save();
pthread_mutex_unlock(&_locker);
}
/**
* Method handling the transfer of the player after a sale
* @param std::string : name of the user who sold the player
* @param std::string : name of the user who won the player
* @param int : id of the player
* @param int : value of the winning bid
* @param Sale : contents of the sale
*/
void PlayerMarket::transfert(std::string fromName, std::string toName, int id, int bidValue, Sale* sale){
User* from = getUserByName(fromName);
Player toTransfert;
if(from == NULL){
if(fromName != net::MSG::GENERATED_BY_MARKET){ //User not connected : load.
Team fromTeam(fromName);
fromTeam.load();
toTransfert = fromTeam.getPlayer(id);
fromTeam.removePlayer(id);
fromTeam.getPayed(bidValue);
fromTeam.save();
}
else{ //Sale generated by market.
toTransfert = sale->getPlayer();
}
}
else{ //User connected : use ref, no need to load.
Team & fromTeam = from->getTeam();
toTransfert = fromTeam.getPlayer(id);
fromTeam.removePlayer(id);
fromTeam.getPayed(bidValue);
fromTeam.save();
}
toTransfert.setOwner(toName);
User* to= getUserByName(toName);
//N.B. : no need to call buy(), since the team alrdy paid the amount in handleNewBid().
if(to == NULL){
Team toTeam(toName);
toTeam.load();
toTeam.addPlayer(toTransfert);
toTeam.save();
}
else{
Team & toTeam = to->getTeam();
toTeam.addPlayer(toTransfert);
toTeam.save();
}
}
/**
* Method handle end of a sale
* @param Sale : sale contents
*/
void PlayerMarket::resolveEndOfSale(Sale * sale){
if(sale->getCurrentBidder().empty() and sale->getOwner() != net::MSG::GENERATED_BY_MARKET){//Player not sold
JSON::Dict toOwner;
toOwner.set("type",net::MSG::END_OF_OWNED_SALE_RAPPORT);
toOwner.set(net::MSG::RAPPORT_SALE_STATUS, net::MSG::PLAYER_NOT_SOLD);
toOwner.set(net::MSG::PLAYER_ID, sale->getID());
sendMessageToUser(sale->getOwner(), toOwner);
}
else if (!(sale->getCurrentBidder().empty())){
transfert(sale->getOwner(),sale->getCurrentBidder(),sale->getID(),sale->getBidValue(), sale);
JSON::Dict toOwner, toWinner;
if(sale->getOwner() != net::MSG::GENERATED_BY_MARKET){
toOwner.set("type",net::MSG::END_OF_OWNED_SALE_RAPPORT);
toOwner.set(net::MSG::RAPPORT_SALE_STATUS, net::MSG::PLAYER_SOLD);
toOwner.set(net::MSG::PLAYER_ID, sale->getID());
toOwner.set(net::MSG::BID_VALUE, sale->getBidValue());
toOwner.set(net::MSG::CURRENT_BIDDER, sale->getCurrentBidder());
sendMessageToUser(sale->getOwner(), toOwner);
}
toWinner.set("type",net::MSG::WON_SALE_RAPPORT);
toWinner.set(net::MSG::PLAYER_ID,sale->getID());
toWinner.set(net::MSG::BID_VALUE, sale->getBidValue());
toWinner.set(net::MSG::SALE_OWNER, sale->getOwner());
sendMessageToUser(sale->getCurrentBidder(), toWinner);
}
}
/// Method retrieving the sale content based on the id of the player
Sale * PlayerMarket::getSale(int id){
for(size_t i = 0; i<_sales.size();++i){
if(_sales[i]->getID() == id){return _sales[i];}
}
return NULL;
}
/// Method retrieving all the sales performed
JSON::Dict PlayerMarket::allSales() {
JSON::Dict response;
response.set("type", net::MSG::PLAYERS_ON_MARKET_LIST);
JSON::List sales;
if(pthread_mutex_lock(&_locker) != 0)
throw "Couldn't acquire lock for PlayerMarket";
for(size_t i=0;i<_sales.size();++i){
sales.append(JSON::Dict(*(_sales[i])));
}
response.set("data", sales);
pthread_mutex_unlock(&_locker);
return response;
}
/// Method adding a player on the market
JSON::Dict PlayerMarket::addPlayer(const JSON::Dict &json){
JSON::Dict response = JSON::Dict();
response.set("type", net::MSG::ADD_PLAYER_ON_MARKET_QUERY);
int player_id = INT(json.get(net::MSG::PLAYER_ID));
int bidValue = INT(json.get(net::MSG::BID_VALUE));
std::string username = STR(json.get(net::MSG::USERNAME));
if(getSale(player_id) != NULL){
response.set("data",net::MSG::PLAYER_ALREADY_ON_MARKET);
}
else if((getUserByName(username)->getTeam().getPlayers().size() + ownedSales(username))<= gameconfig::MIN_PLAYERS){
response.set("data",net::MSG::NOT_ENOUGH_PLAYERS);
}
else{
Player player(player_id, username);
MemoryAccess::load(player);
createSale(player_id, bidValue, player, username);
response.set("data", net::MSG::PLAYER_ADDED_ON_MARKET);
}
return response;
}
/// Method handling the bid on a player
JSON::Dict PlayerMarket::bidOn(const JSON::Dict &json){
JSON::Dict response = JSON::Dict();
response.set("type", net::MSG::BID_ON_PLAYER_QUERY);
std::string username = STR(json.get(net::MSG::USERNAME)).value();
int player_id = INT(json.get(net::MSG::PLAYER_ID));
int bid_value = INT(json.get(net::MSG::BID_VALUE));
if((getUserByName(username)->getTeam().getPlayers().size() + winningSales(username)) >= gameconfig::MAX_PLAYERS)
response.set("data", net::MSG::TOO_MANY_PLAYERS);
else if(getUserByName(username)->getTeam().getFunds() < bid_value){
response.set("data",net::MSG::INSUFFICIENT_FUNDS);
}
else{
try{
if(pthread_mutex_lock(&_locker) != 0)
throw "Couldn't acquire lock for PlayerMarket";
Sale * sale = getSale(player_id);
if(sale == NULL or sale->isOver())
throw bidEndedException();
std::pair<std::string, int> previous = sale->placeBid(username, bid_value);
handleNewBid(previous.first,username,previous.second,bid_value);
response.set("data", net::MSG::BID_PLACED);
}
catch(bidEndedException e){
response.set("data", net::MSG::BID_ENDED);
}
catch(bidValueNotUpdatedException e){
response.set("data", net::MSG::BID_VALUE_NOT_UPDATED);
}
catch(turnException e){
response.set("data", net::MSG::BID_TURN_ERROR);
}
catch(bidOnYourPlayerException e){
response.set("data", net::MSG::CANNOT_BID_ON_YOUR_PLAYER);
}
catch(lastBidderException e){
response.set("data", net::MSG::LAST_BIDDER);
}
pthread_mutex_unlock(&_locker);
}
return response;
}
/// Method handling a new bid on a player
void PlayerMarket::handleNewBid(std::string previousBidder, std::string currentBidder, int previousAmount, int currentAmount){
Team & currentTeam = getUserByName(currentBidder)->getTeam();
currentTeam.buy(currentAmount);
currentTeam.saveInfos();
JSON::Dict toSend;
toSend.set("funds",currentTeam.getFunds());
sendTeamInfos(toSend, getPeerID(currentBidder));
if(!previousBidder.empty()){
User* previousUser = getUserByName(previousBidder);
if (previousUser == NULL){ //User not connected
Team previousTeam(previousBidder);
previousTeam.loadInfos(); //Do not load players nor installations, since it's not needed
previousTeam.getPayed(previousAmount);
previousTeam.saveInfos();
}
else{ //User connected, dynamically saves the change too
Team & previousTeam = previousUser->getTeam();
previousTeam.getPayed(previousAmount);
previousTeam.saveInfos();
JSON::Dict toSend;
toSend.set("funds",previousTeam.getFunds());
sendTeamInfos(toSend, getPeerID(previousBidder));
}
}
}
/// Method sending a message to the user
void PlayerMarket::sendMessageToUser(std::string username, const JSON::Dict & message){
sendMarketMessage(username, message);
}
/// Method computing the number of sales for a user
int PlayerMarket::ownedSales(std::string username){
int res=0;
for(size_t i=0;i<_sales.size();++i){
if(_sales[i]->getOwner() == username){
++res;
}
}
return res;
}
/// Method computing the number of sales won by the usre
int PlayerMarket::winningSales(std::string username){
int res=0;
for(size_t i=0;i<_sales.size();++i){
if(_sales[i]->getCurrentBidder() == username){
++res;
}
}
return res;
}
/// Method handling the addition of a player on the market
void PlayerMarket::addPlayerOnMarket(const JSON::Dict &sale, int peer_id){
Message status(peer_id, addPlayer(sale).clone());
_outbox.push(status);
}
/// Method sending the players for sale
void PlayerMarket::sendPlayersOnMarketList(int peer_id){
Message status(peer_id, allSales().clone());
_outbox.push(status);
}
///Method handling the bid on a player
void PlayerMarket::placeBidOnPlayer(const JSON::Dict &bid, int peer_id){
Message status(peer_id, bidOn(bid).clone());
_outbox.push(status);
}
/// Method handling the transmission of messages to the market
void PlayerMarket::sendMarketMessage(std::string const &username, const JSON::Dict &message){
JSON::Dict toSend;
toSend.set("type",net::MSG::MARKET_MESSAGE);
toSend.set("data",message);
int to_peer = getPeerID(username);
if (to_peer >= 0){
/* User currently connected to server */
Message status(to_peer, toSend.clone());
_outbox.push(status);
} else {
User *user = User::load(username);
if (user != NULL){
user->sendOfflineMsg(toSend);
delete user;
}
}
}
/// Method handling the update refreshrate for the market
void PlayerMarket::timeUpdate()
{
if(pthread_mutex_lock(&_locker) != 0)
throw "Couldn't acquire lock for PlayerMarket";
for(size_t i = 0; i<_sales.size();++i){
Sale & sale = *(_sales[i]);
sale.decTime();
if(sale.getTimeLeft()==0){
sale.resolveEndOfTurn();
if(sale.isOver()){
resolveEndOfSale(&sale);
MemoryAccess::removeObject(sale);
delete _sales[i];
_sales.erase(_sales.begin()+i);
}
}
}
pthread_mutex_unlock(&_locker);
}
/// Method handling the time initialisation for a auction
void PlayerMarket::timeCreateSale()
{
RandomNameGenerator gen;
Player generated;
generated.setName(gen.getRandomName());
generated.setMemberID();
createSale(generated.getMemberID(), generated.estimatedValue(), generated, net::MSG::GENERATED_BY_MARKET);
}