DatabaseHelper.java 9.77 KB
Newer Older
Melledy's avatar
Melledy committed
1
2
3
4
package emu.grasscutter.database;

import java.util.List;

KingRainbow44's avatar
KingRainbow44 committed
5
import com.mongodb.client.result.DeleteResult;
6

7
8
import dev.morphia.query.FindOptions;
import dev.morphia.query.Sort;
KingRainbow44's avatar
KingRainbow44 committed
9
import dev.morphia.query.experimental.filters.Filters;
10
import emu.grasscutter.GameConstants;
Melledy's avatar
Melledy committed
11
import emu.grasscutter.game.Account;
12
import emu.grasscutter.game.avatar.Avatar;
Melledy's avatar
Melledy committed
13
import emu.grasscutter.game.friends.Friendship;
14
import emu.grasscutter.game.gacha.GachaRecord;
15
import emu.grasscutter.game.inventory.GameItem;
16
import emu.grasscutter.game.mail.Mail;
Melledy's avatar
Melledy committed
17
import emu.grasscutter.game.player.Player;
Melledy's avatar
Melledy committed
18
import emu.grasscutter.game.quest.GameMainQuest;
Melledy's avatar
Melledy committed
19

20
21
import static com.mongodb.client.model.Filters.eq;

KingRainbow44's avatar
KingRainbow44 committed
22
public final class DatabaseHelper {
Melledy's avatar
Melledy committed
23
24
25
	public static Account createAccount(String username) {
		return createAccountWithId(username, 0);
	}
KingRainbow44's avatar
KingRainbow44 committed
26

Melledy's avatar
Melledy committed
27
28
29
30
31
32
	public static Account createAccountWithId(String username, int reservedId) {
		// Unique names only
		Account exists = DatabaseHelper.getAccountByName(username);
		if (exists != null) {
			return null;
		}
KingRainbow44's avatar
KingRainbow44 committed
33

Melledy's avatar
Melledy committed
34
35
36
		// Make sure there are no id collisions
		if (reservedId > 0) {
			// Cannot make account with the same uid as the server console
37
			if (reservedId == GameConstants.SERVER_CONSOLE_UID) {
Melledy's avatar
Melledy committed
38
39
40
41
42
43
44
45
46
47
48
49
				return null;
			}
			exists = DatabaseHelper.getAccountByPlayerId(reservedId);
			if (exists != null) {
				return null;
			}
		}

		// Account
		Account account = new Account();
		account.setUsername(username);
		account.setId(Integer.toString(DatabaseManager.getNextId(account)));
KingRainbow44's avatar
KingRainbow44 committed
50

Melledy's avatar
Melledy committed
51
52
		if (reservedId > 0) {
			account.setPlayerId(reservedId);
KingRainbow44's avatar
KingRainbow44 committed
53
		}
Melledy's avatar
Melledy committed
54
55
56
57
58
59
60
61
62
63
64
65

		DatabaseHelper.saveAccount(account);
		return account;
	}

	@Deprecated
	public static Account createAccountWithPassword(String username, String password) {
		// Unique names only
		Account exists = DatabaseHelper.getAccountByName(username);
		if (exists != null) {
			return null;
		}
KingRainbow44's avatar
KingRainbow44 committed
66

Melledy's avatar
Melledy committed
67
68
69
70
71
		// Account
		Account account = new Account();
		account.setId(Integer.toString(DatabaseManager.getNextId(account)));
		account.setUsername(username);
		account.setPassword(password);
KingRainbow44's avatar
KingRainbow44 committed
72
		DatabaseHelper.saveAccount(account);
Melledy's avatar
Melledy committed
73
74
75
76
		return account;
	}

	public static void saveAccount(Account account) {
77
		DatabaseManager.getAccountDatastore().save(account);
Melledy's avatar
Melledy committed
78
	}
KingRainbow44's avatar
KingRainbow44 committed
79

Melledy's avatar
Melledy committed
80
	public static Account getAccountByName(String username) {
81
		return DatabaseManager.getGameDatastore().find(Account.class).filter(Filters.eq("username", username)).first();
Melledy's avatar
Melledy committed
82
	}
KingRainbow44's avatar
KingRainbow44 committed
83

Melledy's avatar
Melledy committed
84
	public static Account getAccountByToken(String token) {
KingRainbow44's avatar
KingRainbow44 committed
85
		if(token == null) return null;
86
		return DatabaseManager.getGameDatastore().find(Account.class).filter(Filters.eq("token", token)).first();
Melledy's avatar
Melledy committed
87
	}
KingRainbow44's avatar
KingRainbow44 committed
88

89
90
	public static Account getAccountBySessionKey(String sessionKey) {
		if(sessionKey == null) return null;
91
		return DatabaseManager.getGameDatastore().find(Account.class).filter(Filters.eq("sessionKey", sessionKey)).first();
92
93
	}

Melledy's avatar
Melledy committed
94
	public static Account getAccountById(String uid) {
95
		return DatabaseManager.getGameDatastore().find(Account.class).filter(Filters.eq("_id", uid)).first();
Melledy's avatar
Melledy committed
96
	}
KingRainbow44's avatar
KingRainbow44 committed
97

98
	public static Account getAccountByPlayerId(int playerId) {
99
		return DatabaseManager.getGameDatastore().find(Account.class).filter(Filters.eq("playerId", playerId)).first();
Melledy's avatar
Melledy committed
100
	}
KingRainbow44's avatar
KingRainbow44 committed
101

102
103
104
105
	public static void deleteAccount(Account target) {
		// To delete an account, we need to also delete all the other documents in the database that reference the account.
		// This should optimally be wrapped inside a transaction, to make sure an error thrown mid-way does not leave the
		// database in an inconsistent state, but unfortunately Mongo only supports that when we have a replica set ...
106

107
		// Delete Mail.class data
108
		DatabaseManager.getGameDatabase().getCollection("mail").deleteMany(eq("ownerUid", target.getPlayerUid()));
109
		// Delete Avatar.class data
110
		DatabaseManager.getGameDatabase().getCollection("avatars").deleteMany(eq("ownerId", target.getPlayerUid()));
111
		// Delete GachaRecord.class data
112
		DatabaseManager.getGameDatabase().getCollection("gachas").deleteMany(eq("ownerId", target.getPlayerUid()));
113
		// Delete GameItem.class data
114
		DatabaseManager.getGameDatabase().getCollection("items").deleteMany(eq("ownerId", target.getPlayerUid()));
Melledy's avatar
Melledy committed
115
		// Delete GameMainQuest.class data
116
		DatabaseManager.getGameDatabase().getCollection("quests").deleteMany(eq("ownerUid", target.getPlayerUid()));
117
118
119
120

		// Delete friendships.
		// Here, we need to make sure to not only delete the deleted account's friendships,
		// but also all friendship entries for that account's friends.
121
122
		DatabaseManager.getGameDatabase().getCollection("friendships").deleteMany(eq("ownerId", target.getPlayerUid()));
		DatabaseManager.getGameDatabase().getCollection("friendships").deleteMany(eq("friendId", target.getPlayerUid()));
123
124

		// Delete the player.
125
		DatabaseManager.getGameDatastore().find(Player.class).filter(Filters.eq("id", target.getPlayerUid())).delete();
126
127

		// Finally, delete the account itself.
128
		DatabaseManager.getGameDatastore().find(Account.class).filter(Filters.eq("id", target.getId())).delete();
Melledy's avatar
Melledy committed
129
	}
KingRainbow44's avatar
KingRainbow44 committed
130

131
	public static List<Player> getAllPlayers() {
132
		return DatabaseManager.getGameDatastore().find(Player.class).stream().toList();
Benjamin Elsdon's avatar
Benjamin Elsdon committed
133
134
	}

135
	public static Player getPlayerById(int id) {
136
		return DatabaseManager.getGameDatastore().find(Player.class).filter(Filters.eq("_id", id)).first();
Melledy's avatar
Melledy committed
137
	}
KingRainbow44's avatar
KingRainbow44 committed
138

Melledy's avatar
Melledy committed
139
	public static boolean checkPlayerExists(int id) {
140
		return DatabaseManager.getGameDatastore().find(Player.class).filter(Filters.eq("_id", id)).first() != null;
Melledy's avatar
Melledy committed
141
	}
KingRainbow44's avatar
KingRainbow44 committed
142

143
	public static synchronized Player createPlayer(Player character, int reservedId) {
Melledy's avatar
Melledy committed
144
		// Check if reserved id
KingRainbow44's avatar
KingRainbow44 committed
145
		int id;
Melledy's avatar
Melledy committed
146
147
		if (reservedId > 0 && !checkPlayerExists(reservedId)) {
			id = reservedId;
148
			character.setUid(id);
Melledy's avatar
Melledy committed
149
150
151
152
153
		} else {
			do {
				id = DatabaseManager.getNextId(character);
			}
			while (checkPlayerExists(id));
154
			character.setUid(id);
Melledy's avatar
Melledy committed
155
156
		}
		// Save to database
157
		DatabaseManager.getGameDatastore().save(character);
Melledy's avatar
Melledy committed
158
159
		return character;
	}
KingRainbow44's avatar
KingRainbow44 committed
160

Melledy's avatar
Melledy committed
161
162
	public static synchronized int getNextPlayerId(int reservedId) {
		// Check if reserved id
KingRainbow44's avatar
KingRainbow44 committed
163
		int id;
Melledy's avatar
Melledy committed
164
165
166
167
		if (reservedId > 0 && !checkPlayerExists(reservedId)) {
			id = reservedId;
		} else {
			do {
168
				id = DatabaseManager.getNextId(Player.class);
Melledy's avatar
Melledy committed
169
170
171
172
173
			}
			while (checkPlayerExists(id));
		}
		return id;
	}
KingRainbow44's avatar
KingRainbow44 committed
174

175
	public static void savePlayer(Player character) {
176
		DatabaseManager.getGameDatastore().save(character);
Melledy's avatar
Melledy committed
177
	}
KingRainbow44's avatar
KingRainbow44 committed
178

179
	public static void saveAvatar(Avatar avatar) {
180
		DatabaseManager.getGameDatastore().save(avatar);
Melledy's avatar
Melledy committed
181
	}
KingRainbow44's avatar
KingRainbow44 committed
182

183
	public static List<Avatar> getAvatars(Player player) {
184
		return DatabaseManager.getGameDatastore().find(Avatar.class).filter(Filters.eq("ownerId", player.getUid())).stream().toList();
Melledy's avatar
Melledy committed
185
	}
KingRainbow44's avatar
KingRainbow44 committed
186

187
	public static void saveItem(GameItem item) {
188
		DatabaseManager.getGameDatastore().save(item);
Melledy's avatar
Melledy committed
189
	}
KingRainbow44's avatar
KingRainbow44 committed
190

191
	public static boolean deleteItem(GameItem item) {
192
		DeleteResult result = DatabaseManager.getGameDatastore().delete(item);
Melledy's avatar
Melledy committed
193
194
		return result.wasAcknowledged();
	}
KingRainbow44's avatar
KingRainbow44 committed
195

196
	public static List<GameItem> getInventoryItems(Player player) {
197
		return DatabaseManager.getGameDatastore().find(GameItem.class).filter(Filters.eq("ownerId", player.getUid())).stream().toList();
Melledy's avatar
Melledy committed
198
	}
199
	
200
	public static List<Friendship> getFriends(Player player) {
201
		return DatabaseManager.getGameDatastore().find(Friendship.class).filter(Filters.eq("ownerId", player.getUid())).stream().toList();
Melledy's avatar
Melledy committed
202
	}
KingRainbow44's avatar
KingRainbow44 committed
203

204
	public static List<Friendship> getReverseFriends(Player player) {
205
		return DatabaseManager.getGameDatastore().find(Friendship.class).filter(Filters.eq("friendId", player.getUid())).stream().toList();
Melledy's avatar
Melledy committed
206
207
208
	}

	public static void saveFriendship(Friendship friendship) {
209
		DatabaseManager.getGameDatastore().save(friendship);
Melledy's avatar
Melledy committed
210
211
212
	}

	public static void deleteFriendship(Friendship friendship) {
213
		DatabaseManager.getGameDatastore().delete(friendship);
Melledy's avatar
Melledy committed
214
215
216
	}

	public static Friendship getReverseFriendship(Friendship friendship) {
217
		return DatabaseManager.getGameDatastore().find(Friendship.class).filter(Filters.and(
KingRainbow44's avatar
KingRainbow44 committed
218
219
220
				Filters.eq("ownerId", friendship.getFriendId()),
				Filters.eq("friendId", friendship.getOwnerId())
		)).first();
Melledy's avatar
Melledy committed
221
	}
memetrollsXD's avatar
memetrollsXD committed
222

223
224
225
226
227
	public static List<GachaRecord> getGachaRecords(int ownerId, int page, int gachaType){
		return getGachaRecords(ownerId, page, gachaType, 10);
	}

	public static List<GachaRecord> getGachaRecords(int ownerId, int page, int gachaType, int pageSize){
228
		return DatabaseManager.getGameDatastore().find(GachaRecord.class).filter(
229
230
231
232
233
234
235
236
237
238
239
240
241
242
			Filters.eq("ownerId", ownerId),
			Filters.eq("gachaType", gachaType)
		).iterator(new FindOptions()
				.sort(Sort.descending("transactionDate"))
				.skip(pageSize * page)
				.limit(pageSize)
		).toList();
	}

	public static long getGachaRecordsMaxPage(int ownerId, int page, int gachaType){
		return getGachaRecordsMaxPage(ownerId, page, gachaType, 10);
	}

	public static long getGachaRecordsMaxPage(int ownerId, int page, int gachaType, int pageSize){
243
		long count = DatabaseManager.getGameDatastore().find(GachaRecord.class).filter(
244
245
246
247
248
249
250
			Filters.eq("ownerId", ownerId),
			Filters.eq("gachaType", gachaType)
		).count();
		return count / 10 + (count % 10 > 0 ? 1 : 0 );
	}

	public static void saveGachaRecord(GachaRecord gachaRecord){
251
		DatabaseManager.getGameDatastore().save(gachaRecord);
252
	}
253
254
	
	public static List<Mail> getAllMail(Player player) {
255
		return DatabaseManager.getGameDatastore().find(Mail.class).filter(Filters.eq("ownerUid", player.getUid())).stream().toList();
256
257
258
	}
	
	public static void saveMail(Mail mail) {
259
		DatabaseManager.getGameDatastore().save(mail);
260
261
262
	}
	
	public static boolean deleteMail(Mail mail) {
263
		DeleteResult result = DatabaseManager.getGameDatastore().delete(mail);
264
265
		return result.wasAcknowledged();
	}
Melledy's avatar
Melledy committed
266
267
	
	public static List<GameMainQuest> getAllQuests(Player player) {
268
		return DatabaseManager.getGameDatastore().find(GameMainQuest.class).filter(Filters.eq("ownerUid", player.getUid())).stream().toList();
Melledy's avatar
Melledy committed
269
270
271
	}
	
	public static void saveQuest(GameMainQuest quest) {
272
		DatabaseManager.getGameDatastore().save(quest);
Melledy's avatar
Melledy committed
273
274
275
	}
	
	public static boolean deleteQuest(GameMainQuest quest) {
276
		return DatabaseManager.getGameDatastore().delete(quest).wasAcknowledged();
Melledy's avatar
Melledy committed
277
	}
Melledy's avatar
Melledy committed
278
}