Commit 01b190bc authored by Magix's avatar Magix Committed by GitHub
Browse files

UPGRADE TO 1.1.0 POG

Merge `development` into `stable`
parents 6b81b888 1beddf16
package emu.grasscutter.data.def; package emu.grasscutter.data.def;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
@ResourceType(name = "PlayerLevelExcelConfigData.json") @ResourceType(name = "PlayerLevelExcelConfigData.json")
public class PlayerLevelData extends GenshinResource { public class PlayerLevelData extends GameResource {
private int Level; private int Level;
private int Exp; private int Exp;
private int RewardId; private int RewardId;
......
...@@ -3,13 +3,13 @@ package emu.grasscutter.data.def; ...@@ -3,13 +3,13 @@ package emu.grasscutter.data.def;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.FightPropData; import emu.grasscutter.data.common.FightPropData;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
@ResourceType(name = "ProudSkillExcelConfigData.json") @ResourceType(name = "ProudSkillExcelConfigData.json")
public class ProudSkillData extends GenshinResource { public class ProudSkillData extends GameResource {
private int ProudSkillId; private int ProudSkillId;
private int ProudSkillGroupId; private int ProudSkillGroupId;
......
package emu.grasscutter.data.def; package emu.grasscutter.data.def;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
@ResourceType(name = "ReliquaryAffixExcelConfigData.json") @ResourceType(name = "ReliquaryAffixExcelConfigData.json")
public class ReliquaryAffixData extends GenshinResource { public class ReliquaryAffixData extends GameResource {
private int Id; private int Id;
private int DepotId; private int DepotId;
......
...@@ -2,14 +2,14 @@ package emu.grasscutter.data.def; ...@@ -2,14 +2,14 @@ package emu.grasscutter.data.def;
import java.util.List; import java.util.List;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@ResourceType(name = "ReliquaryLevelExcelConfigData.json") @ResourceType(name = "ReliquaryLevelExcelConfigData.json")
public class ReliquaryLevelData extends GenshinResource { public class ReliquaryLevelData extends GameResource {
private int id; private int id;
private Int2ObjectMap<Float> propMap; private Int2ObjectMap<Float> propMap;
......
package emu.grasscutter.data.def; package emu.grasscutter.data.def;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
@ResourceType(name = "ReliquaryMainPropExcelConfigData.json") @ResourceType(name = "ReliquaryMainPropExcelConfigData.json")
public class ReliquaryMainPropData extends GenshinResource { public class ReliquaryMainPropData extends GameResource {
private int Id; private int Id;
private int PropDepotId; private int PropDepotId;
......
package emu.grasscutter.data.def; package emu.grasscutter.data.def;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
@ResourceType(name = "ReliquarySetExcelConfigData.json") @ResourceType(name = "ReliquarySetExcelConfigData.json")
public class ReliquarySetData extends GenshinResource { public class ReliquarySetData extends GameResource {
private int SetId; private int SetId;
private int[] SetNeedNum; private int[] SetNeedNum;
private int EquipAffixId; private int EquipAffixId;
......
package emu.grasscutter.data.def;
import java.util.List;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.RewardItemData;
@ResourceType(name = "RewardExcelConfigData.json")
public class RewardData extends GameResource {
public int RewardId;
public List<RewardItemData> RewardItemList;
@Override
public int getId() {
return RewardId;
}
public List<RewardItemData> getRewardItemList() {
return RewardItemList;
}
@Override
public void onLoad() {
}
}
package emu.grasscutter.data.def;
import java.util.Arrays;
import java.util.List;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.common.ItemParamStringData;
@ResourceType(name = "RewardPreviewExcelConfigData.json", loadPriority = LoadPriority.HIGH)
public class RewardPreviewData extends GameResource {
private int Id;
private ItemParamStringData[] PreviewItems;
private ItemParamData[] PreviewItemsArray;
@Override
public int getId() {
return this.Id;
}
public ItemParamData[] getPreviewItems() {
return PreviewItemsArray;
}
@Override
public void onLoad() {
if (this.PreviewItems != null && this.PreviewItems.length > 0) {
this.PreviewItemsArray = Arrays.stream(this.PreviewItems)
.filter(d -> d.getId() > 0 && d.getCount() != null && !d.getCount().isEmpty())
.map(ItemParamStringData::toItemParamData)
.toArray(size -> new ItemParamData[size]);
} else {
this.PreviewItemsArray = new ItemParamData[0];
}
}
}
package emu.grasscutter.data.def; package emu.grasscutter.data.def;
import emu.grasscutter.data.GenshinData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.SceneType; import emu.grasscutter.game.props.SceneType;
@ResourceType(name = "SceneExcelConfigData.json") @ResourceType(name = "SceneExcelConfigData.json")
public class SceneData extends GenshinResource { public class SceneData extends GameResource {
private int Id; private int Id;
private SceneType SceneType; private SceneType Type;
private String ScriptData; private String ScriptData;
@Override @Override
public int getId() { public int getId() {
...@@ -18,7 +19,7 @@ public class SceneData extends GenshinResource { ...@@ -18,7 +19,7 @@ public class SceneData extends GenshinResource {
} }
public SceneType getSceneType() { public SceneType getSceneType() {
return SceneType; return Type;
} }
public String getScriptData() { public String getScriptData() {
...@@ -27,6 +28,6 @@ public class SceneData extends GenshinResource { ...@@ -27,6 +28,6 @@ public class SceneData extends GenshinResource {
@Override @Override
public void onLoad() { public void onLoad() {
} }
} }
package emu.grasscutter.data.def;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.game.shop.ShopInfo;
import java.util.List;
@ResourceType(name = "ShopGoodsExcelConfigData.json")
public class ShopGoodsData extends GameResource {
private int GoodsId;
private int ShopType;
private int ItemId;
private int ItemCount;
private int CostScoin;
private int CostHcoin;
private int CostMcoin;
private List<ItemParamData> CostItems;
private int MinPlayerLevel;
private int MaxPlayerLevel;
private int BuyLimit;
private int SubTabId;
private String RefreshType;
private transient ShopInfo.ShopRefreshType RefreshTypeEnum;
private int RefreshParam;
@Override
public void onLoad() {
if (this.RefreshType == null)
this.RefreshTypeEnum = ShopInfo.ShopRefreshType.NONE;
else {
this.RefreshTypeEnum = switch (this.RefreshType) {
case "SHOP_REFRESH_DAILY" -> ShopInfo.ShopRefreshType.SHOP_REFRESH_DAILY;
case "SHOP_REFRESH_WEEKLY" -> ShopInfo.ShopRefreshType.SHOP_REFRESH_WEEKLY;
case "SHOP_REFRESH_MONTHLY" -> ShopInfo.ShopRefreshType.SHOP_REFRESH_MONTHLY;
default -> ShopInfo.ShopRefreshType.NONE;
};
}
}
@Override
public int getId() {
return getGoodsId();
}
public int getGoodsId() {
return GoodsId;
}
public int getShopType() {
return ShopType;
}
public int getItemId() {
return ItemId;
}
public int getItemCount() {
return ItemCount;
}
public int getCostScoin() {
return CostScoin;
}
public int getCostHcoin() {
return CostHcoin;
}
public int getCostMcoin() {
return CostMcoin;
}
public List<ItemParamData> getCostItems() {
return CostItems;
}
public int getMinPlayerLevel() {
return MinPlayerLevel;
}
public int getMaxPlayerLevel() {
return MaxPlayerLevel;
}
public int getBuyLimit() {
return BuyLimit;
}
public int getSubTabId() {
return SubTabId;
}
public ShopInfo.ShopRefreshType getRefreshType() {
return RefreshTypeEnum;
}
public int getRefreshParam() {
return RefreshParam;
}
}
package emu.grasscutter.data.def;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
@ResourceType(name = "TowerFloorExcelConfigData.json")
public class TowerFloorData extends GameResource {
private int FloorId;
private int FloorIndex;
private int LevelId;
private int OverrideMonsterLevel;
private int TeamNum;
private int FloorLevelConfigId;
@Override
public int getId() {
return this.FloorId;
}
@Override
public void onLoad() {
super.onLoad();
}
public int getFloorId() {
return FloorId;
}
public void setFloorId(int floorId) {
FloorId = floorId;
}
public int getFloorIndex() {
return FloorIndex;
}
public void setFloorIndex(int floorIndex) {
FloorIndex = floorIndex;
}
public int getLevelId() {
return LevelId;
}
public void setLevelId(int levelId) {
LevelId = levelId;
}
public int getOverrideMonsterLevel() {
return OverrideMonsterLevel;
}
public void setOverrideMonsterLevel(int overrideMonsterLevel) {
OverrideMonsterLevel = overrideMonsterLevel;
}
public int getTeamNum() {
return TeamNum;
}
public void setTeamNum(int teamNum) {
TeamNum = teamNum;
}
public int getFloorLevelConfigId() {
return FloorLevelConfigId;
}
public void setFloorLevelConfigId(int floorLevelConfigId) {
FloorLevelConfigId = floorLevelConfigId;
}
}
package emu.grasscutter.data.def;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
@ResourceType(name = "TowerLevelExcelConfigData.json")
public class TowerLevelData extends GameResource {
private int ID;
private int LevelId;
private int LevelIndex;
private int DungeonId;
@Override
public int getId() {
return this.ID;
}
@Override
public void onLoad() {
super.onLoad();
}
public int getID() {
return ID;
}
public void setID(int ID) {
this.ID = ID;
}
public int getLevelId() {
return LevelId;
}
public void setLevelId(int levelId) {
LevelId = levelId;
}
public int getLevelIndex() {
return LevelIndex;
}
public void setLevelIndex(int levelIndex) {
LevelIndex = levelIndex;
}
public int getDungeonId() {
return DungeonId;
}
public void setDungeonId(int dungeonId) {
DungeonId = dungeonId;
}
}
...@@ -4,12 +4,12 @@ import java.util.HashMap; ...@@ -4,12 +4,12 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream; import java.util.stream.Stream;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.CurveInfo; import emu.grasscutter.data.common.CurveInfo;
@ResourceType(name = "WeaponCurveExcelConfigData.json") @ResourceType(name = "WeaponCurveExcelConfigData.json")
public class WeaponCurveData extends GenshinResource { public class WeaponCurveData extends GameResource {
private int Level; private int Level;
private CurveInfo[] CurveInfos; private CurveInfo[] CurveInfos;
......
package emu.grasscutter.data.def; package emu.grasscutter.data.def;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
@ResourceType(name = "WeaponLevelExcelConfigData.json") @ResourceType(name = "WeaponLevelExcelConfigData.json")
public class WeaponLevelData extends GenshinResource { public class WeaponLevelData extends GameResource {
private int Level; private int Level;
private int[] RequiredExps; private int[] RequiredExps;
......
package emu.grasscutter.data.def; package emu.grasscutter.data.def;
import java.util.ArrayList; import java.util.ArrayList;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.FightPropData; import emu.grasscutter.data.common.FightPropData;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
@ResourceType(name = "WeaponPromoteExcelConfigData.json") @ResourceType(name = "WeaponPromoteExcelConfigData.json")
public class WeaponPromoteData extends GenshinResource { public class WeaponPromoteData extends GameResource {
private int WeaponPromoteId; private int WeaponPromoteId;
private int PromoteLevel; private int PromoteLevel;
......
package emu.grasscutter.data.def;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
@ResourceType(name = "WorldLevelExcelConfigData.json")
public class WorldLevelData extends GameResource {
private int Level;
private int MonsterLevel;
@Override
public int getId() {
return this.Level;
}
public int getMonsterLevel() {
return MonsterLevel;
}
@Override
public void onLoad() {
}
}
...@@ -3,7 +3,7 @@ package emu.grasscutter.database; ...@@ -3,7 +3,7 @@ package emu.grasscutter.database;
import dev.morphia.annotations.Entity; import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id; import dev.morphia.annotations.Id;
@Entity(value = "counters", noClassnameStored = true) @Entity(value = "counters", useDiscriminator = false)
public class DatabaseCounter { public class DatabaseCounter {
@Id @Id
private String id; private String id;
......
...@@ -2,41 +2,37 @@ package emu.grasscutter.database; ...@@ -2,41 +2,37 @@ package emu.grasscutter.database;
import java.util.List; import java.util.List;
import com.mongodb.WriteResult; import com.mongodb.client.result.DeleteResult;
import dev.morphia.query.FindOptions; import dev.morphia.query.FindOptions;
import dev.morphia.query.Query; import dev.morphia.query.Sort;
import dev.morphia.query.internal.MorphiaCursor; import dev.morphia.query.experimental.filters.Filters;
import emu.grasscutter.GenshinConstants; import emu.grasscutter.GameConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.GenshinPlayer; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.avatar.GenshinAvatar;
import emu.grasscutter.game.friends.Friendship; import emu.grasscutter.game.friends.Friendship;
import emu.grasscutter.game.inventory.GenshinItem; import emu.grasscutter.game.gacha.GachaRecord;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.mail.Mail;
import emu.grasscutter.game.player.Player;
public class DatabaseHelper { public final class DatabaseHelper {
protected static FindOptions FIND_ONE = new FindOptions().limit(1);
public static Account createAccount(String username) { public static Account createAccount(String username) {
return createAccountWithId(username, 0); return createAccountWithId(username, 0);
} }
public static Account createAccountWithId(String username, int reservedId) { public static Account createAccountWithId(String username, int reservedId) {
// Unique names only // Unique names only
Account exists = DatabaseHelper.getAccountByName(username); Account exists = DatabaseHelper.getAccountByName(username);
if (exists != null) { if (exists != null) {
return null; return null;
} }
// Make sure there are no id collisions // Make sure there are no id collisions
if (reservedId > 0) { if (reservedId > 0) {
// Cannot make account with the same uid as the server console // Cannot make account with the same uid as the server console
if (reservedId == GenshinConstants.SERVER_CONSOLE_UID) { if (reservedId == GameConstants.SERVER_CONSOLE_UID) {
return null; return null;
} }
exists = DatabaseHelper.getAccountByPlayerId(reservedId); exists = DatabaseHelper.getAccountByPlayerId(reservedId);
if (exists != null) { if (exists != null) {
return null; return null;
...@@ -47,10 +43,10 @@ public class DatabaseHelper { ...@@ -47,10 +43,10 @@ public class DatabaseHelper {
Account account = new Account(); Account account = new Account();
account.setUsername(username); account.setUsername(username);
account.setId(Integer.toString(DatabaseManager.getNextId(account))); account.setId(Integer.toString(DatabaseManager.getNextId(account)));
if (reservedId > 0) { if (reservedId > 0) {
account.setPlayerId(reservedId); account.setPlayerId(reservedId);
} }
DatabaseHelper.saveAccount(account); DatabaseHelper.saveAccount(account);
return account; return account;
...@@ -63,65 +59,61 @@ public class DatabaseHelper { ...@@ -63,65 +59,61 @@ public class DatabaseHelper {
if (exists != null) { if (exists != null) {
return null; return null;
} }
// Account // Account
Account account = new Account(); Account account = new Account();
account.setId(Integer.toString(DatabaseManager.getNextId(account))); account.setId(Integer.toString(DatabaseManager.getNextId(account)));
account.setUsername(username); account.setUsername(username);
account.setPassword(password); account.setPassword(password);
DatabaseHelper.saveAccount(account); DatabaseHelper.saveAccount(account);
return account; return account;
} }
public static void saveAccount(Account account) { public static void saveAccount(Account account) {
DatabaseManager.getAccountDatastore().save(account); DatabaseManager.getAccountDatastore().save(account);
} }
public static Account getAccountByName(String username) { public static Account getAccountByName(String username) {
MorphiaCursor<Account> cursor = DatabaseManager.getAccountDatastore().createQuery(Account.class).field("username").equalIgnoreCase(username).find(FIND_ONE); return DatabaseManager.getDatastore().find(Account.class).filter(Filters.eq("username", username)).first();
if (!cursor.hasNext()) return null;
return cursor.next();
} }
public static Account getAccountByToken(String token) { public static Account getAccountByToken(String token) {
if (token == null) return null; if(token == null) return null;
MorphiaCursor<Account> cursor = DatabaseManager.getAccountDatastore().createQuery(Account.class).field("token").equal(token).find(FIND_ONE); return DatabaseManager.getDatastore().find(Account.class).filter(Filters.eq("token", token)).first();
if (!cursor.hasNext()) return null;
return cursor.next();
} }
public static Account getAccountBySessionKey(String sessionKey) {
if(sessionKey == null) return null;
return DatabaseManager.getDatastore().find(Account.class).filter(Filters.eq("sessionKey", sessionKey)).first();
}
public static Account getAccountById(String uid) { public static Account getAccountById(String uid) {
MorphiaCursor<Account> cursor = DatabaseManager.getAccountDatastore().createQuery(Account.class).field("_id").equal(uid).find(FIND_ONE); return DatabaseManager.getDatastore().find(Account.class).filter(Filters.eq("_id", uid)).first();
if (!cursor.hasNext()) return null;
return cursor.next();
} }
public static Account getAccountByPlayerId(int playerId) { public static Account getAccountByPlayerId(int playerId) {
MorphiaCursor<Account> cursor = DatabaseManager.getAccountDatastore().createQuery(Account.class).field("playerId").equal(playerId).find(FIND_ONE); return DatabaseManager.getDatastore().find(Account.class).filter(Filters.eq("playerId", playerId)).first();
if (!cursor.hasNext()) return null;
return cursor.next();
} }
public static boolean deleteAccount(String username) { public static boolean deleteAccount(String username) {
Query<Account> q = DatabaseManager.getAccountDatastore().createQuery(Account.class).field("username").equalIgnoreCase(username); return DatabaseManager.getDatastore().find(Account.class).filter(Filters.eq("username", username)).delete().getDeletedCount() > 0;
return DatabaseManager.getDatastore().findAndDelete(q) != null;
} }
public static GenshinPlayer getPlayerById(int id) { public static List<Player> getAllPlayers() {
Query<GenshinPlayer> query = DatabaseManager.getDatastore().createQuery(GenshinPlayer.class).field("_id").equal(id); return DatabaseManager.getDatastore().find(Player.class).stream().toList();
MorphiaCursor<GenshinPlayer> cursor = query.find(FIND_ONE);
if (!cursor.hasNext()) return null;
return cursor.next();
} }
public static Player getPlayerById(int id) {
return DatabaseManager.getDatastore().find(Player.class).filter(Filters.eq("_id", id)).first();
}
public static boolean checkPlayerExists(int id) { public static boolean checkPlayerExists(int id) {
MorphiaCursor<GenshinPlayer> query = DatabaseManager.getDatastore().createQuery(GenshinPlayer.class).field("_id").equal(id).find(FIND_ONE); return DatabaseManager.getDatastore().find(Player.class).filter(Filters.eq("_id", id)).first() != null;
return query.hasNext();
} }
public static synchronized GenshinPlayer createPlayer(GenshinPlayer character, int reservedId) { public static synchronized Player createPlayer(Player character, int reservedId) {
// Check if reserved id // Check if reserved id
int id = 0; int id;
if (reservedId > 0 && !checkPlayerExists(reservedId)) { if (reservedId > 0 && !checkPlayerExists(reservedId)) {
id = reservedId; id = reservedId;
character.setUid(id); character.setUid(id);
...@@ -136,55 +128,52 @@ public class DatabaseHelper { ...@@ -136,55 +128,52 @@ public class DatabaseHelper {
DatabaseManager.getDatastore().save(character); DatabaseManager.getDatastore().save(character);
return character; return character;
} }
public static synchronized int getNextPlayerId(int reservedId) { public static synchronized int getNextPlayerId(int reservedId) {
// Check if reserved id // Check if reserved id
int id = 0; int id;
if (reservedId > 0 && !checkPlayerExists(reservedId)) { if (reservedId > 0 && !checkPlayerExists(reservedId)) {
id = reservedId; id = reservedId;
} else { } else {
do { do {
id = DatabaseManager.getNextId(GenshinPlayer.class); id = DatabaseManager.getNextId(Player.class);
} }
while (checkPlayerExists(id)); while (checkPlayerExists(id));
} }
return id; return id;
} }
public static void savePlayer(GenshinPlayer character) { public static void savePlayer(Player character) {
DatabaseManager.getDatastore().save(character); DatabaseManager.getDatastore().save(character);
} }
public static void saveAvatar(GenshinAvatar avatar) { public static void saveAvatar(Avatar avatar) {
DatabaseManager.getDatastore().save(avatar); DatabaseManager.getDatastore().save(avatar);
} }
public static List<GenshinAvatar> getAvatars(GenshinPlayer player) { public static List<Avatar> getAvatars(Player player) {
Query<GenshinAvatar> query = DatabaseManager.getDatastore().createQuery(GenshinAvatar.class).filter("ownerId", player.getUid()); return DatabaseManager.getDatastore().find(Avatar.class).filter(Filters.eq("ownerId", player.getUid())).stream().toList();
return query.find().toList();
} }
public static void saveItem(GenshinItem item) { public static void saveItem(GameItem item) {
DatabaseManager.getDatastore().save(item); DatabaseManager.getDatastore().save(item);
} }
public static boolean deleteItem(GenshinItem item) { public static boolean deleteItem(GameItem item) {
WriteResult result = DatabaseManager.getDatastore().delete(item); DeleteResult result = DatabaseManager.getDatastore().delete(item);
return result.wasAcknowledged(); return result.wasAcknowledged();
} }
public static List<GenshinItem> getInventoryItems(GenshinPlayer player) { public static List<GameItem> getInventoryItems(Player player) {
Query<GenshinItem> query = DatabaseManager.getDatastore().createQuery(GenshinItem.class).filter("ownerId", player.getUid()); return DatabaseManager.getDatastore().find(GameItem.class).filter(Filters.eq("ownerId", player.getUid())).stream().toList();
return query.find().toList();
}
public static List<Friendship> getFriends(GenshinPlayer player) {
Query<Friendship> query = DatabaseManager.getDatastore().createQuery(Friendship.class).filter("ownerId", player.getUid());
return query.find().toList();
} }
public static List<Friendship> getReverseFriends(GenshinPlayer player) { public static List<Friendship> getFriends(Player player) {
Query<Friendship> query = DatabaseManager.getDatastore().createQuery(Friendship.class).filter("friendId", player.getUid()); return DatabaseManager.getDatastore().find(Friendship.class).filter(Filters.eq("ownerId", player.getUid())).stream().toList();
return query.find().toList(); }
public static List<Friendship> getReverseFriends(Player player) {
return DatabaseManager.getDatastore().find(Friendship.class).filter(Filters.eq("friendId", player.getUid())).stream().toList();
} }
public static void saveFriendship(Friendship friendship) { public static void saveFriendship(Friendship friendship) {
...@@ -196,13 +185,53 @@ public class DatabaseHelper { ...@@ -196,13 +185,53 @@ public class DatabaseHelper {
} }
public static Friendship getReverseFriendship(Friendship friendship) { public static Friendship getReverseFriendship(Friendship friendship) {
Query<Friendship> query = DatabaseManager.getDatastore().createQuery(Friendship.class); return DatabaseManager.getDatastore().find(Friendship.class).filter(Filters.and(
query.and( Filters.eq("ownerId", friendship.getFriendId()),
query.criteria("ownerId").equal(friendship.getFriendId()), Filters.eq("friendId", friendship.getOwnerId())
query.criteria("friendId").equal(friendship.getOwnerId()) )).first();
); }
MorphiaCursor<Friendship> reverseFriendship = query.find(FIND_ONE);
if (!reverseFriendship.hasNext()) return null; public static List<GachaRecord> getGachaRecords(int ownerId, int page, int gachaType){
return reverseFriendship.next(); return getGachaRecords(ownerId, page, gachaType, 10);
}
public static List<GachaRecord> getGachaRecords(int ownerId, int page, int gachaType, int pageSize){
return DatabaseManager.getDatastore().find(GachaRecord.class).filter(
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){
long count = DatabaseManager.getDatastore().find(GachaRecord.class).filter(
Filters.eq("ownerId", ownerId),
Filters.eq("gachaType", gachaType)
).count();
return count / 10 + (count % 10 > 0 ? 1 : 0 );
}
public static void saveGachaRecord(GachaRecord gachaRecord){
DatabaseManager.getDatastore().save(gachaRecord);
}
public static List<Mail> getAllMail(Player player) {
return DatabaseManager.getDatastore().find(Mail.class).filter(Filters.eq("ownerUid", player.getUid())).stream().toList();
}
public static void saveMail(Mail mail) {
DatabaseManager.getDatastore().save(mail);
}
public static boolean deleteMail(Mail mail) {
DeleteResult result = DatabaseManager.getDatastore().delete(mail);
return result.wasAcknowledged();
} }
} }
package emu.grasscutter.database; package emu.grasscutter.database;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI; import com.mongodb.MongoClientURI;
import com.mongodb.MongoCommandException; import com.mongodb.MongoCommandException;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase; import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoIterable; import com.mongodb.client.MongoIterable;
import dev.morphia.Datastore; import dev.morphia.Datastore;
import dev.morphia.Morphia; import dev.morphia.Morphia;
import dev.morphia.mapping.MapperOptions;
import dev.morphia.query.experimental.filters.Filters;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.Grasscutter.ServerRunMode;
import emu.grasscutter.game.Account; import emu.grasscutter.game.Account;
import emu.grasscutter.game.GenshinPlayer; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.avatar.GenshinAvatar;
import emu.grasscutter.game.friends.Friendship; import emu.grasscutter.game.friends.Friendship;
import emu.grasscutter.game.inventory.GenshinItem; import emu.grasscutter.game.gacha.GachaRecord;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.mail.Mail;
import emu.grasscutter.game.player.Player;
public final class DatabaseManager { public final class DatabaseManager {
private static MongoClient mongoClient; private static MongoClient mongoClient;
private static MongoClient dispatchMongoClient; private static MongoClient dispatchMongoClient;
...@@ -23,25 +30,21 @@ public final class DatabaseManager { ...@@ -23,25 +30,21 @@ public final class DatabaseManager {
private static Datastore dispatchDatastore; private static Datastore dispatchDatastore;
private static final Class<?>[] mappedClasses = new Class<?>[] { private static final Class<?>[] mappedClasses = new Class<?>[] {
DatabaseCounter.class, Account.class, GenshinPlayer.class, GenshinAvatar.class, GenshinItem.class, Friendship.class DatabaseCounter.class, Account.class, Player.class, Avatar.class, GameItem.class, Friendship.class, GachaRecord.class, Mail.class
}; };
public static MongoClient getMongoClient() { public static Datastore getDatastore() {
return mongoClient; return datastore;
} }
public static Datastore getDatastore() { public static MongoDatabase getDatabase() {
return datastore;
}
public static MongoDatabase getDatabase() {
return getDatastore().getDatabase(); return getDatastore().getDatabase();
} }
// Yes. I very dislike this method. However, this will be good for now. // Yes. I very dislike this method. However, this will be good for now.
// TODO: Add dispatch routes for player account management // TODO: Add dispatch routes for player account management
public static Datastore getAccountDatastore() { public static Datastore getAccountDatastore() {
if(Grasscutter.getConfig().RunMode.equalsIgnoreCase("GAME_ONLY")) { if(Grasscutter.getConfig().RunMode == ServerRunMode.GAME_ONLY) {
return dispatchDatastore; return dispatchDatastore;
} else { } else {
return datastore; return datastore;
...@@ -50,27 +53,23 @@ public final class DatabaseManager { ...@@ -50,27 +53,23 @@ public final class DatabaseManager {
public static void initialize() { public static void initialize() {
// Initialize // Initialize
mongoClient = new MongoClient(new MongoClientURI(Grasscutter.getConfig().DatabaseUrl)); MongoClient mongoClient = MongoClients.create(Grasscutter.getConfig().DatabaseUrl);
Morphia morphia = new Morphia();
// TODO Update when migrating to Morphia 2.0
morphia.getMapper().getOptions().setStoreEmpties(true);
morphia.getMapper().getOptions().setStoreNulls(false);
morphia.getMapper().getOptions().setDisableEmbeddedIndexes(true);
// Map // Set mapper options.
morphia.map(mappedClasses); MapperOptions mapperOptions = MapperOptions.builder()
.storeEmpties(true).storeNulls(false).build();
// Build datastore // Create data store.
datastore = morphia.createDatastore(mongoClient, Grasscutter.getConfig().DatabaseCollection); datastore = Morphia.createDatastore(mongoClient, Grasscutter.getConfig().DatabaseCollection, mapperOptions);
// Map classes.
datastore.getMapper().map(mappedClasses);
// Ensure indexes // Ensure indexes
try { try {
datastore.ensureIndexes(); datastore.ensureIndexes();
} catch (MongoCommandException e) { } catch (MongoCommandException exception) {
Grasscutter.getLogger().info("Mongo index error: ", e); Grasscutter.getLogger().info("Mongo index error: ", exception);
// Duplicate index error // Duplicate index error
if (e.getCode() == 85) { if (exception.getCode() == 85) {
// Drop all indexes and re add them // Drop all indexes and re add them
MongoIterable<String> collections = datastore.getDatabase().listCollectionNames(); MongoIterable<String> collections = datastore.getDatabase().listCollectionNames();
for (String name : collections) { for (String name : collections) {
...@@ -81,9 +80,9 @@ public final class DatabaseManager { ...@@ -81,9 +80,9 @@ public final class DatabaseManager {
} }
} }
if(Grasscutter.getConfig().RunMode.equalsIgnoreCase("GAME_ONLY")) { if(Grasscutter.getConfig().RunMode == ServerRunMode.GAME_ONLY) {
dispatchMongoClient = new MongoClient(new MongoClientURI(Grasscutter.getConfig().getGameServerOptions().DispatchServerDatabaseUrl)); dispatchMongoClient = MongoClients.create(Grasscutter.getConfig().getGameServerOptions().DispatchServerDatabaseUrl);
dispatchDatastore = morphia.createDatastore(dispatchMongoClient, Grasscutter.getConfig().getGameServerOptions().DispatchServerDatabaseCollection); dispatchDatastore = Morphia.createDatastore(dispatchMongoClient, Grasscutter.getConfig().getGameServerOptions().DispatchServerDatabaseCollection);
// Ensure indexes for dispatch server // Ensure indexes for dispatch server
try { try {
...@@ -103,9 +102,9 @@ public final class DatabaseManager { ...@@ -103,9 +102,9 @@ public final class DatabaseManager {
} }
} }
} }
public static synchronized int getNextId(Class<?> c) { public static synchronized int getNextId(Class<?> c) {
DatabaseCounter counter = getDatastore().createQuery(DatabaseCounter.class).field("_id").equal(c.getSimpleName()).find().tryNext(); DatabaseCounter counter = getDatastore().find(DatabaseCounter.class).filter(Filters.eq("_id", c.getSimpleName())).first();
if (counter == null) { if (counter == null) {
counter = new DatabaseCounter(c.getSimpleName()); counter = new DatabaseCounter(c.getSimpleName());
} }
...@@ -115,7 +114,7 @@ public final class DatabaseManager { ...@@ -115,7 +114,7 @@ public final class DatabaseManager {
getDatastore().save(counter); getDatastore().save(counter);
} }
} }
public static synchronized int getNextId(Object o) { public static synchronized int getNextId(Object o) {
return getNextId(o.getClass()); return getNextId(o.getClass());
} }
......
package emu.grasscutter.game; package emu.grasscutter.game;
import dev.morphia.annotations.AlsoLoad; import dev.morphia.annotations.*;
import dev.morphia.annotations.Collation;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Indexed;
import dev.morphia.annotations.PreLoad;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import dev.morphia.annotations.IndexOptions;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.bson.Document;
import com.mongodb.DBObject; import com.mongodb.DBObject;
@Entity(value = "accounts", noClassnameStored = true) @Entity(value = "accounts", useDiscriminator = false)
public class Account { public class Account {
@Id private String id; @Id private String id;
...@@ -31,7 +27,7 @@ public class Account { ...@@ -31,7 +27,7 @@ public class Account {
private String token; private String token;
private String sessionKey; // Session token for dispatch server private String sessionKey; // Session token for dispatch server
private List<String> permissions; private List<String> permissions;
@Deprecated @Deprecated
public Account() { public Account() {
this.permissions = new ArrayList<>(); this.permissions = new ArrayList<>();
...@@ -78,7 +74,11 @@ public class Account { ...@@ -78,7 +74,11 @@ public class Account {
} }
public String getEmail() { public String getEmail() {
return email; if(email != null && !email.isEmpty()) {
return email;
} else {
return "";
}
} }
public void setEmail(String email) { public void setEmail(String email) {
...@@ -108,7 +108,10 @@ public class Account { ...@@ -108,7 +108,10 @@ public class Account {
} }
public boolean hasPermission(String permission) { public boolean hasPermission(String permission) {
return this.permissions.contains(permission) || this.permissions.contains("*") ? true : false; return this.permissions.contains(permission) ||
this.permissions.contains("*") ||
(this.permissions.contains("player") || this.permissions.contains("player.*")) && permission.startsWith("player.") ||
(this.permissions.contains("server") || this.permissions.contains("server.*")) && permission.startsWith("server.");
} }
public boolean removePermission(String permission) { public boolean removePermission(String permission) {
...@@ -122,15 +125,15 @@ public class Account { ...@@ -122,15 +125,15 @@ public class Account {
return this.token; return this.token;
} }
public void save() {
DatabaseHelper.saveAccount(this);
}
@PreLoad @PreLoad
public void onLoad(DBObject dbObj) { public void onLoad(Document document) {
// Grant the superuser permissions to accounts created before the permissions update // Grant the superuser permissions to accounts created before the permissions update
if (!dbObj.containsField("permissions")) { if (!document.containsKey("permissions")) {
this.addPermission("*"); this.addPermission("*");
} }
} }
public void save() {
DatabaseHelper.saveAccount(this);
}
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment