Commit 7925d1cd authored by Melledy's avatar Melledy
Browse files

Initial commit

parents
package emu.grasscutter.data.def;
import java.util.ArrayList;
import emu.grasscutter.data.GenshinResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.FightPropData;
import emu.grasscutter.data.common.ItemParamData;
@ResourceType(name = "WeaponPromoteExcelConfigData.json")
public class WeaponPromoteData extends GenshinResource {
private int WeaponPromoteId;
private int PromoteLevel;
private ItemParamData[] CostItems;
private int CoinCost;
private FightPropData[] AddProps;
private int UnlockMaxLevel;
private int RequiredPlayerLevel;
@Override
public int getId() {
return (WeaponPromoteId << 8) + PromoteLevel;
}
public int getWeaponPromoteId() {
return WeaponPromoteId;
}
public int getPromoteLevel() {
return PromoteLevel;
}
public ItemParamData[] getCostItems() {
return CostItems;
}
public int getCoinCost() {
return CoinCost;
}
public FightPropData[] getAddProps() {
return AddProps;
}
public int getUnlockMaxLevel() {
return UnlockMaxLevel;
}
public int getRequiredPlayerLevel() {
return RequiredPlayerLevel;
}
@Override
public void onLoad() {
// Trim item params
ArrayList<ItemParamData> trim = new ArrayList<>(getAddProps().length);
for (ItemParamData itemParam : getCostItems()) {
if (itemParam.getId() == 0) {
continue;
}
trim.add(itemParam);
}
this.CostItems = trim.toArray(new ItemParamData[trim.size()]);
// Trim fight prop data
ArrayList<FightPropData> parsed = new ArrayList<>(getAddProps().length);
for (FightPropData prop : getAddProps()) {
if (prop.getPropType() != null && prop.getValue() != 0f) {
prop.onLoad();
parsed.add(prop);
}
}
this.AddProps = parsed.toArray(new FightPropData[parsed.size()]);
}
}
package emu.grasscutter.database;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
@Entity(value = "counters", noClassnameStored = true)
public class DatabaseCounter {
@Id
private String id;
private int count;
public DatabaseCounter() {}
public DatabaseCounter(String id) {
this.id = id;
this.count = 10000;
}
public int getNextId() {
int id = ++count;
return id;
}
}
package emu.grasscutter.database;
import java.util.List;
import com.mongodb.WriteResult;
import dev.morphia.query.FindOptions;
import dev.morphia.query.Query;
import dev.morphia.query.internal.MorphiaCursor;
import emu.grasscutter.GenshinConstants;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.avatar.GenshinAvatar;
import emu.grasscutter.game.friends.Friendship;
import emu.grasscutter.game.inventory.GenshinItem;
public class DatabaseHelper {
protected static FindOptions FIND_ONE = new FindOptions().limit(1);
public static Account createAccount(String username) {
return createAccountWithId(username, 0);
}
public static Account createAccountWithId(String username, int reservedId) {
// Unique names only
Account exists = DatabaseHelper.getAccountByName(username);
if (exists != null) {
return null;
}
// Make sure there are no id collisions
if (reservedId > 0) {
// Cannot make account with the same uid as the server console
if (reservedId == GenshinConstants.SERVER_CONSOLE_UID) {
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)));
if (reservedId > 0) {
account.setPlayerId(reservedId);
}
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;
}
// Account
Account account = new Account();
account.setId(Integer.toString(DatabaseManager.getNextId(account)));
account.setUsername(username);
account.setPassword(password);
DatabaseHelper.saveAccount(account);
return account;
}
public static void saveAccount(Account account) {
DatabaseManager.getDatastore().save(account);
}
public static Account getAccountByName(String username) {
MorphiaCursor<Account> cursor = DatabaseManager.getDatastore().createQuery(Account.class).field("username").equalIgnoreCase(username).find(FIND_ONE);
if (!cursor.hasNext()) return null;
return cursor.next();
}
public static Account getAccountByToken(String token) {
if (token == null) return null;
MorphiaCursor<Account> cursor = DatabaseManager.getDatastore().createQuery(Account.class).field("token").equal(token).find(FIND_ONE);
if (!cursor.hasNext()) return null;
return cursor.next();
}
public static Account getAccountById(String uid) {
MorphiaCursor<Account> cursor = DatabaseManager.getDatastore().createQuery(Account.class).field("_id").equal(uid).find(FIND_ONE);
if (!cursor.hasNext()) return null;
return cursor.next();
}
private static Account getAccountByPlayerId(int playerId) {
MorphiaCursor<Account> cursor = DatabaseManager.getDatastore().createQuery(Account.class).field("playerId").equal(playerId).find(FIND_ONE);
if (!cursor.hasNext()) return null;
return cursor.next();
}
public static boolean deleteAccount(String username) {
Query<Account> q = DatabaseManager.getDatastore().createQuery(Account.class).field("username").equalIgnoreCase(username);
return DatabaseManager.getDatastore().findAndDelete(q) != null;
}
public static GenshinPlayer getPlayerById(int id) {
Query<GenshinPlayer> query = DatabaseManager.getDatastore().createQuery(GenshinPlayer.class).field("_id").equal(id);
MorphiaCursor<GenshinPlayer> cursor = query.find(FIND_ONE);
if (!cursor.hasNext()) return null;
return cursor.next();
}
public static boolean checkPlayerExists(int id) {
MorphiaCursor<GenshinPlayer> query = DatabaseManager.getDatastore().createQuery(GenshinPlayer.class).field("_id").equal(id).find(FIND_ONE);
return query.hasNext();
}
public static synchronized GenshinPlayer createPlayer(GenshinPlayer character, int reservedId) {
// Check if reserved id
int id = 0;
if (reservedId > 0 && !checkPlayerExists(reservedId)) {
id = reservedId;
character.setId(id);
} else {
do {
id = DatabaseManager.getNextId(character);
}
while (checkPlayerExists(id));
character.setId(id);
}
// Save to database
DatabaseManager.getDatastore().save(character);
return character;
}
public static synchronized int getNextPlayerId(int reservedId) {
// Check if reserved id
int id = 0;
if (reservedId > 0 && !checkPlayerExists(reservedId)) {
id = reservedId;
} else {
do {
id = DatabaseManager.getNextId(GenshinPlayer.class);
}
while (checkPlayerExists(id));
}
return id;
}
public static void savePlayer(GenshinPlayer character) {
DatabaseManager.getDatastore().save(character);
}
public static void saveAvatar(GenshinAvatar avatar) {
DatabaseManager.getDatastore().save(avatar);
}
public static List<GenshinAvatar> getAvatars(GenshinPlayer player) {
Query<GenshinAvatar> query = DatabaseManager.getDatastore().createQuery(GenshinAvatar.class).filter("ownerId", player.getId());
return query.find().toList();
}
public static void saveItem(GenshinItem item) {
DatabaseManager.getDatastore().save(item);
}
public static boolean deleteItem(GenshinItem item) {
WriteResult result = DatabaseManager.getDatastore().delete(item);
return result.wasAcknowledged();
}
public static List<GenshinItem> getInventoryItems(GenshinPlayer player) {
Query<GenshinItem> query = DatabaseManager.getDatastore().createQuery(GenshinItem.class).filter("ownerId", player.getId());
return query.find().toList();
}
public static List<Friendship> getFriends(GenshinPlayer player) {
Query<Friendship> query = DatabaseManager.getDatastore().createQuery(Friendship.class).filter("ownerId", player.getId());
return query.find().toList();
}
public static List<Friendship> getReverseFriends(GenshinPlayer player) {
Query<Friendship> query = DatabaseManager.getDatastore().createQuery(Friendship.class).filter("friendId", player.getId());
return query.find().toList();
}
public static void saveFriendship(Friendship friendship) {
DatabaseManager.getDatastore().save(friendship);
}
public static void deleteFriendship(Friendship friendship) {
DatabaseManager.getDatastore().delete(friendship);
}
public static Friendship getReverseFriendship(Friendship friendship) {
Query<Friendship> query = DatabaseManager.getDatastore().createQuery(Friendship.class);
query.and(
query.criteria("ownerId").equal(friendship.getFriendId()),
query.criteria("friendId").equal(friendship.getOwnerId())
);
MorphiaCursor<Friendship> reverseFriendship = query.find(FIND_ONE);
if (!reverseFriendship.hasNext()) return null;
return reverseFriendship.next();
}
}
package emu.grasscutter.database;
import java.sql.Connection;
import java.sql.SQLException;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.MongoCommandException;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoIterable;
import dev.morphia.Datastore;
import dev.morphia.Morphia;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.avatar.GenshinAvatar;
import emu.grasscutter.game.friends.Friendship;
import emu.grasscutter.game.inventory.GenshinItem;
public class DatabaseManager {
private static MongoClient mongoClient;
private static Morphia morphia;
private static Datastore datastore;
private static Class<?>[] mappedClasses = new Class<?>[] {
DatabaseCounter.class, Account.class, GenshinPlayer.class, GenshinAvatar.class, GenshinItem.class, Friendship.class
};
public static MongoClient getMongoClient() {
return mongoClient;
}
public static Datastore getDatastore() {
return datastore;
}
public static MongoDatabase getDatabase() {
return getDatastore().getDatabase();
}
public static Connection getConnection() throws SQLException {
return null;
}
public static void initialize() {
// Initialize
mongoClient = new MongoClient(new MongoClientURI(Grasscutter.getConfig().DatabaseUrl));
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
morphia.map(mappedClasses);
// Build datastore
datastore = morphia.createDatastore(mongoClient, Grasscutter.getConfig().DatabaseCollection);
// Ensure indexes
try {
datastore.ensureIndexes();
} catch (MongoCommandException e) {
Grasscutter.getLogger().info("Mongo index error: ", e);
// Duplicate index error
if (e.getCode() == 85) {
// Drop all indexes and re add them
MongoIterable<String> collections = datastore.getDatabase().listCollectionNames();
for (String name : collections) {
datastore.getDatabase().getCollection(name).dropIndexes();
}
// Add back indexes
datastore.ensureIndexes();
}
}
}
public static synchronized int getNextId(Class<?> c) {
DatabaseCounter counter = getDatastore().createQuery(DatabaseCounter.class).field("_id").equal(c.getSimpleName()).find().tryNext();
if (counter == null) {
counter = new DatabaseCounter(c.getSimpleName());
}
try {
return counter.getNextId();
} finally {
getDatastore().save(counter);
}
}
public static synchronized int getNextId(Object o) {
return getNextId(o.getClass());
}
}
\ No newline at end of file
package emu.grasscutter.game;
import dev.morphia.annotations.Collation;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import dev.morphia.annotations.Indexed;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.Utils;
import dev.morphia.annotations.IndexOptions;
@Entity(value = "accounts", noClassnameStored = true)
public class Account {
@Id private String id;
@Indexed(options = @IndexOptions(unique = true))
@Collation(locale = "simple", caseLevel = true)
private String username;
private String password; // Unused for now
private int playerId;
private String email;
private String token;
private String sessionKey; // Session token for dispatch server
@Deprecated
public Account() {}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public int getPlayerId() {
return this.playerId;
}
public void setPlayerId(int playerId) {
this.playerId = playerId;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getSessionKey() {
return this.sessionKey;
}
public String generateSessionKey() {
this.sessionKey = Utils.bytesToHex(Crypto.createSessionKey(32));
this.save();
return this.sessionKey;
}
// TODO make unique
public String generateLoginToken() {
this.token = Utils.bytesToHex(Crypto.createSessionKey(32));
this.save();
return this.token;
}
public void save() {
DatabaseHelper.saveAccount(this);
}
}
package emu.grasscutter.game;
public class CoopRequest {
private final GenshinPlayer requester;
private final long requestTime;
private final long expireTime;
public CoopRequest(GenshinPlayer requester) {
this.requester = requester;
this.requestTime = System.currentTimeMillis();
this.expireTime = this.requestTime + 10000;
}
public GenshinPlayer getRequester() {
return requester;
}
public long getRequestTime() {
return requestTime;
}
public long getExpireTime() {
return expireTime;
}
public boolean isExpired() {
return System.currentTimeMillis() > getExpireTime();
}
}
This diff is collapsed.
package emu.grasscutter.game;
import java.util.ArrayList;
import java.util.List;
import emu.grasscutter.net.packet.GenshinPacket;
import emu.grasscutter.net.proto.ForwardTypeOuterClass.ForwardType;
public class InvokeHandler<T> {
private final List<T> entryListForwardAll;
private final List<T> entryListForwardAllExceptCur;
private final List<T> entryListForwardHost;
private final Class<? extends GenshinPacket> packetClass;
public InvokeHandler(Class<? extends GenshinPacket> packetClass) {
this.entryListForwardAll = new ArrayList<>();
this.entryListForwardAllExceptCur = new ArrayList<>();
this.entryListForwardHost = new ArrayList<>();
this.packetClass = packetClass;
}
public synchronized void addEntry(ForwardType forward, T entry) {
switch (forward) {
case ForwardToAll:
entryListForwardAll.add(entry);
break;
case ForwardToAllExceptCur:
case ForwardToAllExistExceptCur:
entryListForwardAllExceptCur.add(entry);
break;
case ForwardToHost:
entryListForwardHost.add(entry);
break;
default:
break;
}
}
public synchronized void update(GenshinPlayer player) {
if (player.getWorld() == null) {
this.entryListForwardAll.clear();
this.entryListForwardAllExceptCur.clear();
this.entryListForwardHost.clear();
return;
}
try {
if (entryListForwardAll.size() > 0) {
GenshinPacket packet = packetClass.getDeclaredConstructor(List.class).newInstance(this.entryListForwardAll);
player.getWorld().broadcastPacket(packet);
this.entryListForwardAll.clear();
}
if (entryListForwardAllExceptCur.size() > 0) {
GenshinPacket packet = packetClass.getDeclaredConstructor(List.class).newInstance(this.entryListForwardAllExceptCur);
player.getWorld().broadcastPacketToOthers(player, packet);
this.entryListForwardAllExceptCur.clear();
}
if (entryListForwardHost.size() > 0) {
GenshinPacket packet = packetClass.getDeclaredConstructor(List.class).newInstance(this.entryListForwardHost);
player.getWorld().getHost().sendPacket(packet);
this.entryListForwardHost.clear();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package emu.grasscutter.game;
import java.util.ArrayList;
import java.util.List;
import emu.grasscutter.GenshinConstants;
import emu.grasscutter.game.avatar.GenshinAvatar;
public class TeamInfo {
private String name;
private List<Integer> avatars;
public TeamInfo() {
this.name = "";
this.avatars = new ArrayList<>(GenshinConstants.MAX_AVATARS_IN_TEAM);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Integer> getAvatars() {
return avatars;
}
public int size() {
return avatars.size();
}
public boolean contains(GenshinAvatar avatar) {
return getAvatars().contains(avatar.getAvatarId());
}
public boolean addAvatar(GenshinAvatar avatar) {
if (size() >= GenshinConstants.MAX_AVATARS_IN_TEAM || contains(avatar)) {
return false;
}
getAvatars().add(avatar.getAvatarId());
return true;
}
public boolean removeAvatar(int slot) {
if (size() <= 1) {
return false;
}
getAvatars().remove(slot);
return true;
}
public void copyFrom(TeamInfo team) {
copyFrom(team, GenshinConstants.MAX_AVATARS_IN_TEAM);
}
public void copyFrom(TeamInfo team, int maxTeamSize) {
// Clear
this.getAvatars().clear();
// Copy from team
int len = Math.min(team.getAvatars().size(), maxTeamSize);
for (int i = 0; i < len; i++) {
int id = team.getAvatars().get(i);
this.getAvatars().add(id);
}
}
}
This diff is collapsed.
This diff is collapsed.
package emu.grasscutter.game.avatar;
public class AvatarProfileData {
private int avatarId;
private int level;
public AvatarProfileData(GenshinAvatar avatar) {
this.update(avatar);
}
public int getAvatarId() {
return avatarId;
}
public int getLevel() {
return level;
}
public void update(GenshinAvatar avatar) {
this.avatarId = avatar.getAvatarId();
this.level = avatar.getLevel();
}
}
package emu.grasscutter.game.avatar;
import java.util.stream.Stream;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public enum AvatarStat {
FIGHT_PROP_NONE(0),
FIGHT_PROP_BASE_HP(1),
FIGHT_PROP_HP(2),
FIGHT_PROP_HP_PERCENT(3),
FIGHT_PROP_BASE_ATTACK(4),
FIGHT_PROP_ATTACK(5),
FIGHT_PROP_ATTACK_PERCENT(6),
FIGHT_PROP_BASE_DEFENSE(7),
FIGHT_PROP_DEFENSE(8),
FIGHT_PROP_DEFENSE_PERCENT(9),
FIGHT_PROP_BASE_SPEED(10),
FIGHT_PROP_SPEED_PERCENT(11),
FIGHT_PROP_HP_MP_PERCENT(12),
FIGHT_PROP_ATTACK_MP_PERCENT(13),
FIGHT_PROP_CRITICAL(20),
FIGHT_PROP_ANTI_CRITICAL(21),
FIGHT_PROP_CRITICAL_HURT(22),
FIGHT_PROP_CHARGE_EFFICIENCY(23),
FIGHT_PROP_ADD_HURT(24),
FIGHT_PROP_SUB_HURT(25),
FIGHT_PROP_HEAL_ADD(26),
FIGHT_PROP_HEALED_ADD(27),
FIGHT_PROP_ELEMENT_MASTERY(28),
FIGHT_PROP_PHYSICAL_SUB_HURT(29),
FIGHT_PROP_PHYSICAL_ADD_HURT(30),
FIGHT_PROP_DEFENCE_IGNORE_RATIO(31),
FIGHT_PROP_DEFENCE_IGNORE_DELTA(32),
FIGHT_PROP_FIRE_ADD_HURT(40),
FIGHT_PROP_ELEC_ADD_HURT(41),
FIGHT_PROP_WATER_ADD_HURT(42),
FIGHT_PROP_GRASS_ADD_HURT(43),
FIGHT_PROP_WIND_ADD_HURT(44),
FIGHT_PROP_ROCK_ADD_HURT(45),
FIGHT_PROP_ICE_ADD_HURT(46),
FIGHT_PROP_HIT_HEAD_ADD_HURT(47),
FIGHT_PROP_FIRE_SUB_HURT(50),
FIGHT_PROP_ELEC_SUB_HURT(51),
FIGHT_PROP_WATER_SUB_HURT(52),
FIGHT_PROP_GRASS_SUB_HURT(53),
FIGHT_PROP_WIND_SUB_HURT(54),
FIGHT_PROP_ROCK_SUB_HURT(55),
FIGHT_PROP_ICE_SUB_HURT(56),
FIGHT_PROP_EFFECT_HIT(60),
FIGHT_PROP_EFFECT_RESIST(61),
FIGHT_PROP_FREEZE_RESIST(62),
FIGHT_PROP_TORPOR_RESIST(63),
FIGHT_PROP_DIZZY_RESIST(64),
FIGHT_PROP_FREEZE_SHORTEN(65),
FIGHT_PROP_TORPOR_SHORTEN(66),
FIGHT_PROP_DIZZY_SHORTEN(67),
FIGHT_PROP_MAX_FIRE_ENERGY(70),
FIGHT_PROP_MAX_ELEC_ENERGY(71),
FIGHT_PROP_MAX_WATER_ENERGY(72),
FIGHT_PROP_MAX_GRASS_ENERGY(73),
FIGHT_PROP_MAX_WIND_ENERGY(74),
FIGHT_PROP_MAX_ICE_ENERGY(75),
FIGHT_PROP_MAX_ROCK_ENERGY(76),
FIGHT_PROP_SKILL_CD_MINUS_RATIO(80),
FIGHT_PROP_SHIELD_COST_MINUS_RATIO(81),
FIGHT_PROP_CUR_FIRE_ENERGY(1000),
FIGHT_PROP_CUR_ELEC_ENERGY(1001),
FIGHT_PROP_CUR_WATER_ENERGY(1002),
FIGHT_PROP_CUR_GRASS_ENERGY(1003),
FIGHT_PROP_CUR_WIND_ENERGY(1004),
FIGHT_PROP_CUR_ICE_ENERGY(1005),
FIGHT_PROP_CUR_ROCK_ENERGY(1006),
FIGHT_PROP_CUR_HP(1010),
FIGHT_PROP_MAX_HP(2000),
FIGHT_PROP_CUR_ATTACK(2001),
FIGHT_PROP_CUR_DEFENSE(2002),
FIGHT_PROP_CUR_SPEED(2003),
FIGHT_PROP_NONEXTRA_ATTACK(3000),
FIGHT_PROP_NONEXTRA_DEFENSE(3001),
FIGHT_PROP_NONEXTRA_CRITICAL(3002),
FIGHT_PROP_NONEXTRA_ANTI_CRITICAL(3003),
FIGHT_PROP_NONEXTRA_CRITICAL_HURT(3004),
FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY(3005),
FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY(3006),
FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT(3007),
FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT(3008),
FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT(3009),
FIGHT_PROP_NONEXTRA_WATER_ADD_HURT(3010),
FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT(3011),
FIGHT_PROP_NONEXTRA_WIND_ADD_HURT(3012),
FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT(3013),
FIGHT_PROP_NONEXTRA_ICE_ADD_HURT(3014),
FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT(3015),
FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT(3016),
FIGHT_PROP_NONEXTRA_WATER_SUB_HURT(3017),
FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT(3018),
FIGHT_PROP_NONEXTRA_WIND_SUB_HURT(3019),
FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT(3020),
FIGHT_PROP_NONEXTRA_ICE_SUB_HURT(3021),
FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO(3022),
FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO(3023),
FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT(3024);
private final int id;
private static final Int2ObjectMap<AvatarStat> map = new Int2ObjectOpenHashMap<>();
static {
Stream.of(values()).forEach(e -> map.put(e.getId(), e));
}
private AvatarStat(int id) {
this.id = id;
}
public int getId() {
return id;
}
public static AvatarStat getStatById(int value) {
return map.getOrDefault(value, FIGHT_PROP_NONE);
}
}
package emu.grasscutter.game.avatar;
import java.util.Iterator;
import java.util.List;
import emu.grasscutter.data.GenshinData;
import emu.grasscutter.data.def.AvatarData;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.inventory.GenshinItem;
import emu.grasscutter.server.packet.send.PacketAvatarChangeCostumeNotify;
import emu.grasscutter.server.packet.send.PacketAvatarFlycloakChangeNotify;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
public class AvatarStorage implements Iterable<GenshinAvatar> {
private final GenshinPlayer player;
private final Int2ObjectMap<GenshinAvatar> avatars;
private final Long2ObjectMap<GenshinAvatar> avatarsGuid;
public AvatarStorage(GenshinPlayer player) {
this.player = player;
this.avatars = new Int2ObjectOpenHashMap<>();
this.avatarsGuid = new Long2ObjectOpenHashMap<>();
}
public GenshinPlayer getPlayer() {
return player;
}
public Int2ObjectMap<GenshinAvatar> getAvatars() {
return avatars;
}
public int getAvatarCount() {
return this.avatars.size();
}
public GenshinAvatar getAvatarById(int id) {
return getAvatars().get(id);
}
public GenshinAvatar getAvatarByGuid(long id) {
return avatarsGuid.get(id);
}
public boolean hasAvatar(int id) {
return getAvatars().containsKey(id);
}
public boolean addAvatar(GenshinAvatar avatar) {
if (avatar.getAvatarData() == null || this.hasAvatar(avatar.getAvatarId())) {
return false;
}
// Set owner first
avatar.setOwner(getPlayer());
// Put into maps
this.avatars.put(avatar.getAvatarId(), avatar);
this.avatarsGuid.put(avatar.getGuid(), avatar);
avatar.save();
return true;
}
public void addStartingWeapon(GenshinAvatar avatar) {
// Make sure avatar owner is this player
if (avatar.getPlayer() != this.getPlayer()) {
return;
}
// Create weapon
GenshinItem weapon = new GenshinItem(avatar.getAvatarData().getInitialWeapon());
if (weapon.getItemData() != null) {
this.getPlayer().getInventory().addItem(weapon);
avatar.equipItem(weapon, true);
}
}
public boolean wearFlycloak(long avatarGuid, int flycloakId) {
GenshinAvatar avatar = this.getAvatarByGuid(avatarGuid);
if (avatar == null || !getPlayer().getFlyCloakList().contains(flycloakId)) {
return false;
}
avatar.setFlyCloak(flycloakId);
avatar.save();
// Update
getPlayer().sendPacket(new PacketAvatarFlycloakChangeNotify(avatar));
return true;
}
public boolean changeCostume(long avatarGuid, int costumeId) {
GenshinAvatar avatar = this.getAvatarByGuid(avatarGuid);
if (avatar == null) {
return false;
}
if (costumeId != 0 && !getPlayer().getCostumeList().contains(costumeId)) {
return false;
}
// TODO make sure avatar can wear costume
avatar.setCostume(costumeId);
avatar.save();
// Update entity
EntityAvatar entity = avatar.getAsEntity();
if (entity == null) {
entity = new EntityAvatar(avatar);
getPlayer().sendPacket(new PacketAvatarChangeCostumeNotify(entity));
} else {
getPlayer().getWorld().broadcastPacket(new PacketAvatarChangeCostumeNotify(entity));
}
// Done
return true;
}
public void loadFromDatabase() {
List<GenshinAvatar> avatars = DatabaseHelper.getAvatars(getPlayer());
for (GenshinAvatar avatar : avatars) {
// Should never happen
if (avatar.getObjectId() == null) {
continue;
}
AvatarData avatarData = GenshinData.getAvatarDataMap().get(avatar.getAvatarId());
if (avatarData == null) {
continue;
}
// Set ownerships
avatar.setAvatarData(avatarData);
avatar.setOwner(getPlayer());
// Force recalc of const boosted skills
avatar.recalcProudSkillBonusMap();
// Add to avatar storage
this.avatars.put(avatar.getAvatarId(), avatar);
this.avatarsGuid.put(avatar.getGuid(), avatar);
}
}
public void postLoad() {
for (GenshinAvatar avatar : this) {
// Weapon check
if (avatar.getWeapon() == null) {
this.addStartingWeapon(avatar);
}
// Recalc stats
avatar.recalcStats();
}
}
@Override
public Iterator<GenshinAvatar> iterator() {
return getAvatars().values().iterator();
}
}
This diff is collapsed.
package emu.grasscutter.game.dungeons;
import emu.grasscutter.server.game.GameServer;
public class DungeonManager {
private final GameServer server;
public DungeonManager(GameServer server) {
this.server = server;
}
public GameServer getServer() {
return server;
}
}
This diff is collapsed.
package emu.grasscutter.game.entity;
import emu.grasscutter.game.World;
public abstract class EntityGadget extends GenshinEntity {
public EntityGadget(World world) {
super(world);
}
public abstract int getGadgetId();
@Override
public void onDeath(int killerId) {
}
}
This diff is collapsed.
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