Commit dce13cf6 authored by Magix's avatar Magix Committed by GitHub
Browse files

Merge branch 'development' into plugin-system

parents 832c460a b6fedcf2
...@@ -197,8 +197,8 @@ public final class SetStatsCommand implements CommandHandler { ...@@ -197,8 +197,8 @@ public final class SetStatsCommand implements CommandHandler {
float eelec = Integer.parseInt(args.get(1)); float eelec = Integer.parseInt(args.get(1));
EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity();
float elec = eelec / 10000; float elec = eelec / 10000;
entity.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL_HURT, elec); entity.setFightProperty(FightProperty.FIGHT_PROP_ELEC_ADD_HURT, elec);
entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CRITICAL_HURT)); entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_ELEC_ADD_HURT));
float igelec = elec * 100; float igelec = elec * 100;
CommandHandler.sendMessage(sender, "Electro DMG Bonus set to " + igelec + "%"); CommandHandler.sendMessage(sender, "Electro DMG Bonus set to " + igelec + "%");
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
......
...@@ -2,6 +2,7 @@ package emu.grasscutter.command.commands; ...@@ -2,6 +2,7 @@ package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.def.AvatarSkillDepotData;
import emu.grasscutter.game.GenshinPlayer; import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.avatar.GenshinAvatar; import emu.grasscutter.game.avatar.GenshinAvatar;
import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityAvatar;
...@@ -21,8 +22,9 @@ public class TalentCommand implements CommandHandler { ...@@ -21,8 +22,9 @@ public class TalentCommand implements CommandHandler {
return; return;
} }
if (args.size() < 0 || args.size() < 1){ if (args.size() < 1){
CommandHandler.sendMessage(sender, "To set talent level: /talent set <talentID> <value>"); CommandHandler.sendMessage(sender, "To set talent level: /talent set <talentID> <value>");
CommandHandler.sendMessage(sender, "Another way to set talent level: /talent <n or e or q> <value>");
CommandHandler.sendMessage(sender, "To get talent ID: /talent getid"); CommandHandler.sendMessage(sender, "To get talent ID: /talent getid");
return; return;
} }
...@@ -31,6 +33,7 @@ public class TalentCommand implements CommandHandler { ...@@ -31,6 +33,7 @@ public class TalentCommand implements CommandHandler {
switch (cmdSwitch) { switch (cmdSwitch) {
default: default:
CommandHandler.sendMessage(sender, "To set talent level: /talent set <talentID> <value>"); CommandHandler.sendMessage(sender, "To set talent level: /talent set <talentID> <value>");
CommandHandler.sendMessage(sender, "Another way to set talent level: /talent <n or e or q> <value>");
CommandHandler.sendMessage(sender, "To get talent ID: /talent getid"); CommandHandler.sendMessage(sender, "To get talent ID: /talent getid");
return; return;
case "set": case "set":
...@@ -90,6 +93,45 @@ public class TalentCommand implements CommandHandler { ...@@ -90,6 +93,45 @@ public class TalentCommand implements CommandHandler {
return; return;
} }
break;
case "n": case "e": case "q":
try {
EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity();
GenshinAvatar avatar = entity.getAvatar();
AvatarSkillDepotData SkillDepot = avatar.getData().getSkillDepot();
int skillId;
switch (cmdSwitch) {
default:
skillId = SkillDepot.getSkills().get(0);
break;
case "e":
skillId = SkillDepot.getSkills().get(1);
break;
case "q":
skillId = SkillDepot.getEnergySkill();
break;
}
int nextLevel = Integer.parseInt(args.get(1));
int currentLevel = avatar.getSkillLevelMap().get(skillId);
if (args.size() < 1){
CommandHandler.sendMessage(sender, "To set talent level: /talent <n or e or q> <value>");
return;
}
if (nextLevel > 16){
CommandHandler.sendMessage(sender, "Invalid talent level. Level should be lower than 16");
return;
}
// Upgrade skill
avatar.getSkillLevelMap().put(skillId, nextLevel);
avatar.save();
// Packet
sender.sendPacket(new PacketAvatarSkillChangeNotify(avatar, skillId, currentLevel, nextLevel));
sender.sendPacket(new PacketAvatarSkillUpgradeRsp(avatar, skillId, currentLevel, nextLevel));
CommandHandler.sendMessage(sender, "Set this talent to " + nextLevel + ".");
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, "Invalid talent level.");
return;
}
break; break;
case "getid": case "getid":
EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity(); EntityAvatar entity = sender.getTeamManager().getCurrentAvatarEntity();
......
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.utils.Position;
import java.util.List;
@Command(label = "teleport", usage = "teleport <x> <y> <z>", aliases = {"tp"},
description = "Change the player's position.", permission = "player.teleport")
public class TelePortCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer sender, List<String> args) {
if (sender == null) {
CommandHandler.sendMessage(null, "Run this command in-game.");
return;
}
if (args.size() < 3){
CommandHandler.sendMessage(sender, "Usage: /tp <x> <y> <z> [scene id]");
return;
}
try {
float x = 0f;
float y = 0f;
float z = 0f;
if (args.get(0).contains("~")) {
if (args.get(0).equals("~")) {
x = sender.getPos().getX();
} else {
x = Float.parseFloat(args.get(0).replace("~", "")) + sender.getPos().getX();
}
} else {
x = Float.parseFloat(args.get(0));
}
if (args.get(1).contains("~")) {
if (args.get(1).equals("~")) {
y = sender.getPos().getY();
} else {
y = Float.parseFloat(args.get(1).replace("~", "")) + sender.getPos().getY();
}
} else {
y = Float.parseFloat(args.get(1));
}
if (args.get(2).contains("~")) {
if (args.get(2).equals("~")) {
z = sender.getPos().getZ();
} else {
z = Float.parseFloat(args.get(2).replace("~", "")) + sender.getPos().getZ();
}
} else {
z = Float.parseFloat(args.get(2));
}
int sceneId = sender.getSceneId();
if (args.size() == 4){
sceneId = Integer.parseInt(args.get(3));
}
Position target = new Position(x, y, z);
boolean result = sender.getWorld().transferPlayerToScene(sender, sceneId, target);
if (!result) {
CommandHandler.sendMessage(sender, "Invalid position.");
}
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, "Invalid position.");
}
}
}
...@@ -31,6 +31,7 @@ public class GenshinData { ...@@ -31,6 +31,7 @@ public class GenshinData {
private static final Int2ObjectMap<AvatarSkillDepotData> avatarSkillDepotDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarSkillDepotData> avatarSkillDepotDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<AvatarSkillData> avatarSkillDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarSkillData> avatarSkillDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap = new Int2ObjectLinkedOpenHashMap<>();
private static final Int2ObjectMap<AvatarFetterLevelData> avatarFetterLevelDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<AvatarPromoteData> avatarPromoteDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarPromoteData> avatarPromoteDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<AvatarTalentData> avatarTalentDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarTalentData> avatarTalentDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<ProudSkillData> proudSkillDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ProudSkillData> proudSkillDataMap = new Int2ObjectOpenHashMap<>();
...@@ -57,6 +58,8 @@ public class GenshinData { ...@@ -57,6 +58,8 @@ public class GenshinData {
private static final Int2ObjectMap<SceneData> sceneDataMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap<SceneData> sceneDataMap = new Int2ObjectLinkedOpenHashMap<>();
private static final Int2ObjectMap<FetterData> fetterDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<FetterData> fetterDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<FetterCharacterCardData> fetterCharacterCardDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<RewardData> rewardDataMap = new Int2ObjectOpenHashMap<>();
// Cache // Cache
private static Map<Integer, List<Integer>> fetters = new HashMap<>(); private static Map<Integer, List<Integer>> fetters = new HashMap<>();
...@@ -114,6 +117,14 @@ public class GenshinData { ...@@ -114,6 +117,14 @@ public class GenshinData {
return playerLevelDataMap; return playerLevelDataMap;
} }
public static Int2ObjectMap<AvatarFetterLevelData> getAvatarFetterLevelDataMap() {
return avatarFetterLevelDataMap;
}
public static Int2ObjectMap<FetterCharacterCardData> getFetterCharacterCardDataMap() {
return fetterCharacterCardDataMap;
}
public static Int2ObjectMap<AvatarLevelData> getAvatarLevelDataMap() { public static Int2ObjectMap<AvatarLevelData> getAvatarLevelDataMap() {
return avatarLevelDataMap; return avatarLevelDataMap;
} }
...@@ -175,6 +186,11 @@ public class GenshinData { ...@@ -175,6 +186,11 @@ public class GenshinData {
AvatarLevelData levelData = avatarLevelDataMap.get(level); AvatarLevelData levelData = avatarLevelDataMap.get(level);
return levelData != null ? levelData.getExp() : 0; return levelData != null ? levelData.getExp() : 0;
} }
public static int getAvatarFetterLevelExpRequired(int level) {
AvatarFetterLevelData levelData = avatarFetterLevelDataMap.get(level);
return levelData != null ? levelData.getExp() : 0;
}
public static Int2ObjectMap<ProudSkillData> getProudSkillDataMap() { public static Int2ObjectMap<ProudSkillData> getProudSkillDataMap() {
return proudSkillDataMap; return proudSkillDataMap;
...@@ -228,6 +244,10 @@ public class GenshinData { ...@@ -228,6 +244,10 @@ public class GenshinData {
return sceneDataMap; return sceneDataMap;
} }
public static Int2ObjectMap<RewardData> getRewardDataMap() {
return rewardDataMap;
}
public static Map<Integer, List<Integer>> getFetterDataEntries() { public static Map<Integer, List<Integer>> getFetterDataEntries() {
if (fetters.isEmpty()) { if (fetters.isEmpty()) {
fetterDataMap.forEach((k, v) -> { fetterDataMap.forEach((k, v) -> {
......
package emu.grasscutter.data.common;
import java.util.List;
public class OpenCondData {
private String CondType;
private List<Integer> ParamList;
public String getCondType() {
return CondType;
}
public void setCondType(String condType) {
CondType = condType;
}
public List<Integer> getParamList() {
return ParamList;
}
public void setParamList(List<Integer> paramList) {
ParamList = paramList;
}
}
package emu.grasscutter.data.common;
public class RewardItemData {
private int ItemId;
private int ItemCount;
public int getItemId() {
return ItemId;
}
public void setItemId(int itemId) {
ItemId = itemId;
}
public int getItemCount() {
return ItemCount;
}
public void setItemCount(int itemCount) {
ItemCount = itemCount;
}
}
...@@ -57,6 +57,8 @@ public class AvatarData extends GenshinResource { ...@@ -57,6 +57,8 @@ public class AvatarData extends GenshinResource {
private IntList abilities; private IntList abilities;
private List<Integer> fetters; private List<Integer> fetters;
private int nameCardRewardId;
private int nameCardId;
@Override @Override
public int getId(){ public int getId(){
...@@ -199,12 +201,28 @@ public class AvatarData extends GenshinResource { ...@@ -199,12 +201,28 @@ public class AvatarData extends GenshinResource {
return fetters; return fetters;
} }
public int getNameCardRewardId() {
return nameCardRewardId;
}
public int getNameCardId() {
return nameCardId;
}
@Override @Override
public void onLoad() { public void onLoad() {
this.skillDepot = GenshinData.getAvatarSkillDepotDataMap().get(this.SkillDepotId); this.skillDepot = GenshinData.getAvatarSkillDepotDataMap().get(this.SkillDepotId);
// Get fetters from GenshinData // Get fetters from GenshinData
this.fetters = GenshinData.getFetterDataEntries().get(this.Id); this.fetters = GenshinData.getFetterDataEntries().get(this.Id);
if (GenshinData.getFetterCharacterCardDataMap().get(this.Id) != null) {
this.nameCardRewardId = GenshinData.getFetterCharacterCardDataMap().get(this.Id).getRewardId();
}
if (GenshinData.getRewardDataMap().get(this.nameCardRewardId) != null) {
this.nameCardId = GenshinData.getRewardDataMap().get(this.nameCardRewardId).getRewardItemList().get(0).getItemId();
}
int size = GenshinData.getAvatarCurveDataMap().size(); int size = GenshinData.getAvatarCurveDataMap().size();
this.hpGrowthCurve = new float[size]; this.hpGrowthCurve = new float[size];
......
package emu.grasscutter.data.def;
import emu.grasscutter.data.GenshinResource;
import emu.grasscutter.data.ResourceType;
@ResourceType(name = "AvatarFettersLevelExcelConfigData.json")
public class AvatarFetterLevelData extends GenshinResource {
private int FetterLevel;
private int NeedExp;
@Override
public int getId() {
return this.FetterLevel;
}
public int getLevel() {
return FetterLevel;
}
public int getExp() {
return NeedExp;
}
}
package emu.grasscutter.data.def;
import emu.grasscutter.data.GenshinResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority;
@ResourceType(name = "FetterCharacterCardExcelConfigData.json", loadPriority = LoadPriority.HIGHEST)
public class FetterCharacterCardData extends GenshinResource {
private int AvatarId;
private int RewardId;
@Override
public int getId() {
return AvatarId;
}
public int getRewardId() {
return RewardId;
}
@Override
public void onLoad() {
}
}
package emu.grasscutter.data.def; package emu.grasscutter.data.def;
import java.util.List;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GenshinResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.OpenCondData;
@ResourceType(name = {"FetterInfoExcelConfigData.json", "FettersExcelConfigData.json", "FetterStoryExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST) @ResourceType(name = {"FetterInfoExcelConfigData.json", "FettersExcelConfigData.json", "FetterStoryExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST)
public class FetterData extends GenshinResource { public class FetterData extends GenshinResource {
private int AvatarId; private int AvatarId;
private int FetterId; private int FetterId;
private List<OpenCondData> OpenCond;
@Override @Override
public int getId() { public int getId() {
...@@ -18,6 +22,10 @@ public class FetterData extends GenshinResource { ...@@ -18,6 +22,10 @@ public class FetterData extends GenshinResource {
return AvatarId; return AvatarId;
} }
public List<OpenCondData> getOpenConds() {
return OpenCond;
}
@Override @Override
public void onLoad() { public void onLoad() {
} }
......
package emu.grasscutter.data.def;
import java.util.List;
import emu.grasscutter.data.GenshinResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.RewardItemData;
@ResourceType(name = "RewardExcelConfigData.json")
public class RewardData extends GenshinResource {
public int RewardId;
public List<RewardItemData> RewardItemList;
@Override
public int getId() {
return RewardId;
}
public List<RewardItemData> getRewardItemList() {
return RewardItemList;
}
@Override
public void onLoad() {
}
}
...@@ -101,7 +101,7 @@ public final class DatabaseManager { ...@@ -101,7 +101,7 @@ public final class DatabaseManager {
} }
public static synchronized int getNextId(Class<?> c) { public static synchronized int getNextId(Class<?> c) {
DatabaseCounter counter = getDatastore().find(DatabaseCounter.class).filter(Filters.eq("_id", c.getName())).first(); 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());
} }
......
package emu.grasscutter.game; package emu.grasscutter.game;
import java.util.*;
import dev.morphia.annotations.*; import dev.morphia.annotations.*;
import emu.grasscutter.GenshinConstants; import emu.grasscutter.GenshinConstants;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
...@@ -23,7 +21,6 @@ import emu.grasscutter.game.props.ActionReason; ...@@ -23,7 +21,6 @@ import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.net.packet.GenshinPacket; import emu.grasscutter.net.packet.GenshinPacket;
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
import emu.grasscutter.net.proto.BirthdayOuterClass.Birthday;
import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry; import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
import emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage; import emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage;
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType; import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
...@@ -35,38 +32,18 @@ import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; ...@@ -35,38 +32,18 @@ import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
import emu.grasscutter.net.proto.WorldPlayerLocationInfoOuterClass.WorldPlayerLocationInfo; import emu.grasscutter.net.proto.WorldPlayerLocationInfoOuterClass.WorldPlayerLocationInfo;
import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketAbilityInvocationsNotify; import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.server.packet.send.PacketAvatarAddNotify;
import emu.grasscutter.server.packet.send.PacketAvatarDataNotify;
import emu.grasscutter.server.packet.send.PacketAvatarGainCostumeNotify;
import emu.grasscutter.server.packet.send.PacketAvatarGainFlycloakNotify;
import emu.grasscutter.server.packet.send.PacketClientAbilityInitFinishNotify;
import emu.grasscutter.server.packet.send.PacketCombatInvocationsNotify;
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
import emu.grasscutter.server.packet.send.PacketItemAddHintNotify;
import emu.grasscutter.server.packet.send.PacketOpenStateUpdateNotify;
import emu.grasscutter.server.packet.send.PacketPlayerApplyEnterMpResultNotify;
import emu.grasscutter.server.packet.send.PacketPlayerDataNotify;
import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
import emu.grasscutter.server.packet.send.PacketPlayerPropNotify;
import emu.grasscutter.server.packet.send.PacketPlayerStoreNotify;
import emu.grasscutter.server.packet.send.PacketPrivateChatNotify;
import emu.grasscutter.server.packet.send.PacketScenePlayerLocationNotify;
import emu.grasscutter.server.packet.send.PacketSetNameCardRsp;
import emu.grasscutter.server.packet.send.PacketStoreWeightLimitNotify;
import emu.grasscutter.server.packet.send.PacketUnlockNameCardNotify;
import emu.grasscutter.server.packet.send.PacketWorldPlayerLocationNotify;
import emu.grasscutter.server.packet.send.PacketWorldPlayerRTTNotify;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
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;
import java.util.*;
@Entity(value = "players", useDiscriminator = false) @Entity(value = "players", useDiscriminator = false)
public class GenshinPlayer { public class GenshinPlayer {
@Id private int id; @Id private int id;
@Indexed(options = @IndexOptions(unique = true)) private String accountId; @Indexed(options = @IndexOptions(unique = true)) private String accountId;
@Transient private Account account; @Transient private Account account;
private String nickname; private String nickname;
private String signature; private String signature;
...@@ -75,12 +52,12 @@ public class GenshinPlayer { ...@@ -75,12 +52,12 @@ public class GenshinPlayer {
private Position pos; private Position pos;
private Position rotation; private Position rotation;
private PlayerBirthday birthday; private PlayerBirthday birthday;
private Map<Integer, Integer> properties; private Map<Integer, Integer> properties;
private Set<Integer> nameCardList; private Set<Integer> nameCardList;
private Set<Integer> flyCloakList; private Set<Integer> flyCloakList;
private Set<Integer> costumeList; private Set<Integer> costumeList;
@Transient private long nextGuid = 0; @Transient private long nextGuid = 0;
@Transient private int peerId; @Transient private int peerId;
@Transient private World world; @Transient private World world;
...@@ -89,32 +66,34 @@ public class GenshinPlayer { ...@@ -89,32 +66,34 @@ public class GenshinPlayer {
@Transient private AvatarStorage avatars; @Transient private AvatarStorage avatars;
@Transient private Inventory inventory; @Transient private Inventory inventory;
@Transient private FriendsList friendsList; @Transient private FriendsList friendsList;
private TeamManager teamManager; private TeamManager teamManager;
private PlayerGachaInfo gachaInfo; private PlayerGachaInfo gachaInfo;
private PlayerProfile playerProfile; private PlayerProfile playerProfile;
private MpSettingType mpSetting = MpSettingType.MpSettingEnterAfterApply; private MpSettingType mpSetting = MpSettingType.MpSettingEnterAfterApply;
private boolean showAvatar; private boolean showAvatar;
private ArrayList<AvatarProfileData> shownAvatars; private ArrayList<AvatarProfileData> shownAvatars;
private Set<Integer> rewardedLevels;
private int sceneId; private int sceneId;
private int regionId; private int regionId;
private int mainCharacterId; private int mainCharacterId;
private boolean godmode; private boolean godmode;
@Transient private boolean paused; @Transient private boolean paused;
@Transient private int enterSceneToken; @Transient private int enterSceneToken;
@Transient private SceneLoadState sceneState; @Transient private SceneLoadState sceneState;
@Transient private boolean hasSentAvatarDataNotify; @Transient private boolean hasSentAvatarDataNotify;
@Transient private long nextSendPlayerLocTime = 0; @Transient private long nextSendPlayerLocTime = 0;
@Transient private final Int2ObjectMap<CoopRequest> coopRequests; @Transient private final Int2ObjectMap<CoopRequest> coopRequests;
@Transient private final InvokeHandler<CombatInvokeEntry> combatInvokeHandler; @Transient private final InvokeHandler<CombatInvokeEntry> combatInvokeHandler;
@Transient private final InvokeHandler<AbilityInvokeEntry> abilityInvokeHandler; @Transient private final InvokeHandler<AbilityInvokeEntry> abilityInvokeHandler;
@Transient private final InvokeHandler<AbilityInvokeEntry> clientAbilityInitFinishHandler; @Transient private final InvokeHandler<AbilityInvokeEntry> clientAbilityInitFinishHandler;
@Deprecated @SuppressWarnings({ "rawtypes", "unchecked" }) // Morphia only! @Deprecated
public GenshinPlayer() { @SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only!
public GenshinPlayer() {
this.inventory = new Inventory(this); this.inventory = new Inventory(this);
this.avatars = new AvatarStorage(this); this.avatars = new AvatarStorage(this);
this.friendsList = new FriendsList(this); this.friendsList = new FriendsList(this);
...@@ -127,24 +106,25 @@ public class GenshinPlayer { ...@@ -127,24 +106,25 @@ public class GenshinPlayer {
} }
this.properties.put(prop.getId(), 0); this.properties.put(prop.getId(), 0);
} }
this.gachaInfo = new PlayerGachaInfo(); this.gachaInfo = new PlayerGachaInfo();
this.nameCardList = new HashSet<>(); this.nameCardList = new HashSet<>();
this.flyCloakList = new HashSet<>(); this.flyCloakList = new HashSet<>();
this.costumeList = new HashSet<>(); this.costumeList = new HashSet<>();
this.setSceneId(3); this.setSceneId(3);
this.setRegionId(1); this.setRegionId(1);
this.sceneState = SceneLoadState.NONE; this.sceneState = SceneLoadState.NONE;
this.coopRequests = new Int2ObjectOpenHashMap<>(); this.coopRequests = new Int2ObjectOpenHashMap<>();
this.combatInvokeHandler = new InvokeHandler(PacketCombatInvocationsNotify.class); this.combatInvokeHandler = new InvokeHandler(PacketCombatInvocationsNotify.class);
this.abilityInvokeHandler = new InvokeHandler(PacketAbilityInvocationsNotify.class); this.abilityInvokeHandler = new InvokeHandler(PacketAbilityInvocationsNotify.class);
this.clientAbilityInitFinishHandler = new InvokeHandler(PacketClientAbilityInitFinishNotify.class); this.clientAbilityInitFinishHandler = new InvokeHandler(PacketClientAbilityInitFinishNotify.class);
this.birthday = new PlayerBirthday(); this.birthday = new PlayerBirthday();
this.rewardedLevels = new HashSet<>();
} }
// On player creation // On player creation
public GenshinPlayer(GameSession session) { public GenshinPlayer(GameSession session) {
this(); this();
...@@ -176,7 +156,7 @@ public class GenshinPlayer { ...@@ -176,7 +156,7 @@ public class GenshinPlayer {
public void setUid(int id) { public void setUid(int id) {
this.id = id; this.id = id;
} }
public long getNextGenshinGuid() { public long getNextGenshinGuid() {
long nextId = ++this.nextGuid; long nextId = ++this.nextGuid;
return ((long) this.getUid() << 32) + nextId; return ((long) this.getUid() << 32) + nextId;
...@@ -198,23 +178,23 @@ public class GenshinPlayer { ...@@ -198,23 +178,23 @@ public class GenshinPlayer {
public void setSession(GameSession session) { public void setSession(GameSession session) {
this.session = session; this.session = session;
} }
public boolean isOnline() { public boolean isOnline() {
return this.getSession() != null && this.getSession().isActive(); return this.getSession() != null && this.getSession().isActive();
} }
public GameServer getServer() { public GameServer getServer() {
return this.getSession().getServer(); return this.getSession().getServer();
} }
public synchronized World getWorld() { public synchronized World getWorld() {
return this.world; return this.world;
} }
public synchronized void setWorld(World world) { public synchronized void setWorld(World world) {
this.world = world; this.world = world;
} }
public GenshinScene getScene() { public GenshinScene getScene() {
return scene; return scene;
} }
...@@ -235,7 +215,7 @@ public class GenshinPlayer { ...@@ -235,7 +215,7 @@ public class GenshinPlayer {
this.nickname = nickName; this.nickname = nickName;
this.updateProfile(); this.updateProfile();
} }
public int getHeadImage() { public int getHeadImage() {
return headImage; return headImage;
} }
...@@ -257,71 +237,71 @@ public class GenshinPlayer { ...@@ -257,71 +237,71 @@ public class GenshinPlayer {
public Position getPos() { public Position getPos() {
return pos; return pos;
} }
public Position getRotation() { public Position getRotation() {
return rotation; return rotation;
} }
public int getLevel() { public int getLevel() {
return this.getProperty(PlayerProperty.PROP_PLAYER_LEVEL); return this.getProperty(PlayerProperty.PROP_PLAYER_LEVEL);
} }
public int getExp() { public int getExp() {
return this.getProperty(PlayerProperty.PROP_PLAYER_EXP); return this.getProperty(PlayerProperty.PROP_PLAYER_EXP);
} }
public int getWorldLevel() { public int getWorldLevel() {
return this.getProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL); return this.getProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL);
} }
public int getPrimogems() { public int getPrimogems() {
return this.getProperty(PlayerProperty.PROP_PLAYER_HCOIN); return this.getProperty(PlayerProperty.PROP_PLAYER_HCOIN);
} }
public void setPrimogems(int primogem) { public void setPrimogems(int primogem) {
this.setProperty(PlayerProperty.PROP_PLAYER_HCOIN, primogem); this.setProperty(PlayerProperty.PROP_PLAYER_HCOIN, primogem);
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_HCOIN)); this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_HCOIN));
} }
public int getMora() { public int getMora() {
return this.getProperty(PlayerProperty.PROP_PLAYER_SCOIN); return this.getProperty(PlayerProperty.PROP_PLAYER_SCOIN);
} }
public void setMora(int mora) { public void setMora(int mora) {
this.setProperty(PlayerProperty.PROP_PLAYER_SCOIN, mora); this.setProperty(PlayerProperty.PROP_PLAYER_SCOIN, mora);
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_SCOIN)); this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_SCOIN));
} }
private int getExpRequired(int level) { private int getExpRequired(int level) {
PlayerLevelData levelData = GenshinData.getPlayerLevelDataMap().get(level); PlayerLevelData levelData = GenshinData.getPlayerLevelDataMap().get(level);
return levelData != null ? levelData.getExp() : 0; return levelData != null ? levelData.getExp() : 0;
} }
private float getExpModifier() { private float getExpModifier() {
return Grasscutter.getConfig().getGameServerOptions().getGameRates().ADVENTURE_EXP_RATE; return Grasscutter.getConfig().getGameServerOptions().getGameRates().ADVENTURE_EXP_RATE;
} }
// Affected by exp rate // Affected by exp rate
public void earnExp(int exp) { public void earnExp(int exp) {
addExpDirectly((int) (exp * getExpModifier())); addExpDirectly((int) (exp * getExpModifier()));
} }
// Directly give player exp // Directly give player exp
public void addExpDirectly(int gain) { public void addExpDirectly(int gain) {
boolean hasLeveledUp = false; boolean hasLeveledUp = false;
int level = getLevel(); int level = getLevel();
int exp = getExp(); int exp = getExp();
int reqExp = getExpRequired(level); int reqExp = getExpRequired(level);
exp += gain; exp += gain;
while (exp >= reqExp && reqExp > 0) { while (exp >= reqExp && reqExp > 0) {
exp -= reqExp; exp -= reqExp;
level += 1; level += 1;
reqExp = getExpRequired(level); reqExp = getExpRequired(level);
hasLeveledUp = true; hasLeveledUp = true;
} }
if (hasLeveledUp) { if (hasLeveledUp) {
// Set level property // Set level property
this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, level); this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, level);
...@@ -330,18 +310,18 @@ public class GenshinPlayer { ...@@ -330,18 +310,18 @@ public class GenshinPlayer {
// Update player with packet // Update player with packet
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_LEVEL)); this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_LEVEL));
} }
// Set exp // Set exp
this.setProperty(PlayerProperty.PROP_PLAYER_EXP, exp); this.setProperty(PlayerProperty.PROP_PLAYER_EXP, exp);
// Update player with packet // Update player with packet
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_EXP)); this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_EXP));
} }
private void updateProfile() { private void updateProfile() {
getProfile().syncWithCharacter(this); getProfile().syncWithCharacter(this);
} }
public boolean isFirstLoginEnterScene() { public boolean isFirstLoginEnterScene() {
return !this.hasSentAvatarDataNotify; return !this.hasSentAvatarDataNotify;
} }
...@@ -364,11 +344,11 @@ public class GenshinPlayer { ...@@ -364,11 +344,11 @@ public class GenshinPlayer {
public Map<Integer, Integer> getProperties() { public Map<Integer, Integer> getProperties() {
return properties; return properties;
} }
public void setProperty(PlayerProperty prop, int value) { public void setProperty(PlayerProperty prop, int value) {
getProperties().put(prop.getId(), value); getProperties().put(prop.getId(), value);
} }
public int getProperty(PlayerProperty prop) { public int getProperty(PlayerProperty prop) {
return getProperties().get(prop.getId()); return getProperties().get(prop.getId());
} }
...@@ -376,11 +356,11 @@ public class GenshinPlayer { ...@@ -376,11 +356,11 @@ public class GenshinPlayer {
public Set<Integer> getFlyCloakList() { public Set<Integer> getFlyCloakList() {
return flyCloakList; return flyCloakList;
} }
public Set<Integer> getCostumeList() { public Set<Integer> getCostumeList() {
return costumeList; return costumeList;
} }
public Set<Integer> getNameCardList() { public Set<Integer> getNameCardList() {
return this.nameCardList; return this.nameCardList;
} }
...@@ -388,7 +368,7 @@ public class GenshinPlayer { ...@@ -388,7 +368,7 @@ public class GenshinPlayer {
public MpSettingType getMpSetting() { public MpSettingType getMpSetting() {
return mpSetting; return mpSetting;
} }
public synchronized Int2ObjectMap<CoopRequest> getCoopRequests() { public synchronized Int2ObjectMap<CoopRequest> getCoopRequests() {
return coopRequests; return coopRequests;
} }
...@@ -396,7 +376,7 @@ public class GenshinPlayer { ...@@ -396,7 +376,7 @@ public class GenshinPlayer {
public InvokeHandler<CombatInvokeEntry> getCombatInvokeHandler() { public InvokeHandler<CombatInvokeEntry> getCombatInvokeHandler() {
return this.combatInvokeHandler; return this.combatInvokeHandler;
} }
public InvokeHandler<AbilityInvokeEntry> getAbilityInvokeHandler() { public InvokeHandler<AbilityInvokeEntry> getAbilityInvokeHandler() {
return this.abilityInvokeHandler; return this.abilityInvokeHandler;
} }
...@@ -412,11 +392,11 @@ public class GenshinPlayer { ...@@ -412,11 +392,11 @@ public class GenshinPlayer {
public AvatarStorage getAvatars() { public AvatarStorage getAvatars() {
return avatars; return avatars;
} }
public Inventory getInventory() { public Inventory getInventory() {
return inventory; return inventory;
} }
public FriendsList getFriendsList() { public FriendsList getFriendsList() {
return this.friendsList; return this.friendsList;
} }
...@@ -469,7 +449,7 @@ public class GenshinPlayer { ...@@ -469,7 +449,7 @@ public class GenshinPlayer {
public void setPaused(boolean newPauseState) { public void setPaused(boolean newPauseState) {
boolean oldPauseState = this.paused; boolean oldPauseState = this.paused;
this.paused = newPauseState; this.paused = newPauseState;
if (newPauseState && !oldPauseState) { if (newPauseState && !oldPauseState) {
this.onPause(); this.onPause();
} else if (oldPauseState && !newPauseState) { } else if (oldPauseState && !newPauseState) {
...@@ -484,7 +464,7 @@ public class GenshinPlayer { ...@@ -484,7 +464,7 @@ public class GenshinPlayer {
public void setSceneLoadState(SceneLoadState sceneState) { public void setSceneLoadState(SceneLoadState sceneState) {
this.sceneState = sceneState; this.sceneState = sceneState;
} }
public boolean isInMultiplayer() { public boolean isInMultiplayer() {
return this.getWorld() != null && this.getWorld().isMultiplayer(); return this.getWorld() != null && this.getWorld().isMultiplayer();
} }
...@@ -504,7 +484,7 @@ public class GenshinPlayer { ...@@ -504,7 +484,7 @@ public class GenshinPlayer {
public void setRegionId(int regionId) { public void setRegionId(int regionId) {
this.regionId = regionId; this.regionId = regionId;
} }
public boolean inGodmode() { public boolean inGodmode() {
return godmode; return godmode;
} }
...@@ -523,11 +503,11 @@ public class GenshinPlayer { ...@@ -523,11 +503,11 @@ public class GenshinPlayer {
public void addAvatar(GenshinAvatar avatar) { public void addAvatar(GenshinAvatar avatar) {
boolean result = getAvatars().addAvatar(avatar); boolean result = getAvatars().addAvatar(avatar);
if (result) { if (result) {
// Add starting weapon // Add starting weapon
getAvatars().addStartingWeapon(avatar); getAvatars().addStartingWeapon(avatar);
// Try adding to team if possible // Try adding to team if possible
//List<EntityAvatar> currentTeam = this.getTeamManager().getCurrentTeam(); //List<EntityAvatar> currentTeam = this.getTeamManager().getCurrentTeam();
boolean addedToTeam = false; boolean addedToTeam = false;
...@@ -537,7 +517,7 @@ public class GenshinPlayer { ...@@ -537,7 +517,7 @@ public class GenshinPlayer {
addedToTeam = currentTeam addedToTeam = currentTeam
} }
*/ */
// Done // Done
if (hasSentAvatarDataNotify()) { if (hasSentAvatarDataNotify()) {
// Recalc stats // Recalc stats
...@@ -549,55 +529,56 @@ public class GenshinPlayer { ...@@ -549,55 +529,56 @@ public class GenshinPlayer {
// Failed adding avatar // Failed adding avatar
} }
} }
public void addFlycloak(int flycloakId) { public void addFlycloak(int flycloakId) {
this.getFlyCloakList().add(flycloakId); this.getFlyCloakList().add(flycloakId);
this.sendPacket(new PacketAvatarGainFlycloakNotify(flycloakId)); this.sendPacket(new PacketAvatarGainFlycloakNotify(flycloakId));
} }
public void addCostume(int costumeId) { public void addCostume(int costumeId) {
this.getCostumeList().add(costumeId); this.getCostumeList().add(costumeId);
this.sendPacket(new PacketAvatarGainCostumeNotify(costumeId)); this.sendPacket(new PacketAvatarGainCostumeNotify(costumeId));
} }
public void addNameCard(int nameCardId) { public void addNameCard(int nameCardId) {
this.getNameCardList().add(nameCardId); this.getNameCardList().add(nameCardId);
this.sendPacket(new PacketUnlockNameCardNotify(nameCardId)); this.sendPacket(new PacketUnlockNameCardNotify(nameCardId));
} }
public void setNameCard(int nameCardId) { public void setNameCard(int nameCardId) {
if (!this.getNameCardList().contains(nameCardId)) { if (!this.getNameCardList().contains(nameCardId)) {
return; return;
} }
this.setNameCardId(nameCardId); this.setNameCardId(nameCardId);
this.sendPacket(new PacketSetNameCardRsp(nameCardId)); this.sendPacket(new PacketSetNameCardRsp(nameCardId));
} }
public void dropMessage(Object message) { public void dropMessage(Object message) {
this.sendPacket(new PacketPrivateChatNotify(GenshinConstants.SERVER_CONSOLE_UID, getUid(), message.toString())); this.sendPacket(new PacketPrivateChatNotify(GenshinConstants.SERVER_CONSOLE_UID, getUid(), message.toString()));
} }
/** /**
* Sends a message to another player. * Sends a message to another player.
* @param sender The sender of the message. *
* @param sender The sender of the message.
* @param message The message to send. * @param message The message to send.
*/ */
public void sendMessage(GenshinPlayer sender, Object message) { public void sendMessage(GenshinPlayer sender, Object message) {
this.sendPacket(new PacketPrivateChatNotify(sender.getUid(), this.getUid(), message.toString())); this.sendPacket(new PacketPrivateChatNotify(sender.getUid(), this.getUid(), message.toString()));
} }
public void interactWith(int gadgetEntityId) { public void interactWith(int gadgetEntityId) {
GenshinEntity entity = getScene().getEntityById(gadgetEntityId); GenshinEntity entity = getScene().getEntityById(gadgetEntityId);
if (entity == null) { if (entity == null) {
return; return;
} }
// Delete // Delete
entity.getScene().removeEntity(entity); entity.getScene().removeEntity(entity);
// Handle // Handle
if (entity instanceof EntityItem) { if (entity instanceof EntityItem) {
// Pick item // Pick item
...@@ -610,24 +591,24 @@ public class GenshinPlayer { ...@@ -610,24 +591,24 @@ public class GenshinPlayer {
this.sendPacket(new PacketItemAddHintNotify(item, ActionReason.SubfieldDrop)); this.sendPacket(new PacketItemAddHintNotify(item, ActionReason.SubfieldDrop));
} }
} }
return; return;
} }
public void onPause() { public void onPause() {
} }
public void onUnpause() { public void onUnpause() {
} }
public void sendPacket(GenshinPacket packet) { public void sendPacket(GenshinPacket packet) {
if (this.hasSentAvatarDataNotify) { if (this.hasSentAvatarDataNotify) {
this.getSession().send(packet); this.getSession().send(packet);
} }
} }
public OnlinePlayerInfo getOnlinePlayerInfo() { public OnlinePlayerInfo getOnlinePlayerInfo() {
OnlinePlayerInfo.Builder onlineInfo = OnlinePlayerInfo.newBuilder() OnlinePlayerInfo.Builder onlineInfo = OnlinePlayerInfo.newBuilder()
.setUid(this.getUid()) .setUid(this.getUid())
...@@ -637,17 +618,17 @@ public class GenshinPlayer { ...@@ -637,17 +618,17 @@ public class GenshinPlayer {
.setNameCardId(this.getNameCardId()) .setNameCardId(this.getNameCardId())
.setSignature(this.getSignature()) .setSignature(this.getSignature())
.setAvatar(HeadImage.newBuilder().setAvatarId(this.getHeadImage())); .setAvatar(HeadImage.newBuilder().setAvatarId(this.getHeadImage()));
if (this.getWorld() != null) { if (this.getWorld() != null) {
onlineInfo.setCurPlayerNumInWorld(this.getWorld().getPlayers().indexOf(this) + 1); onlineInfo.setCurPlayerNumInWorld(this.getWorld().getPlayers().indexOf(this) + 1);
} else { } else {
onlineInfo.setCurPlayerNumInWorld(1); onlineInfo.setCurPlayerNumInWorld(1);
} }
return onlineInfo.build(); return onlineInfo.build();
} }
public PlayerBirthday getBirthday(){ public PlayerBirthday getBirthday() {
return this.birthday; return this.birthday;
} }
...@@ -656,6 +637,18 @@ public class GenshinPlayer { ...@@ -656,6 +637,18 @@ public class GenshinPlayer {
this.updateProfile(); this.updateProfile();
} }
public boolean hasBirthday() {
return this.birthday.getDay() > 0;
}
public Set<Integer> getRewardedLevels() {
return rewardedLevels;
}
public void setRewardedLevels(Set<Integer> rewardedLevels) {
this.rewardedLevels = rewardedLevels;
}
public SocialDetail.Builder getSocialDetail() { public SocialDetail.Builder getSocialDetail() {
SocialDetail.Builder social = SocialDetail.newBuilder() SocialDetail.Builder social = SocialDetail.newBuilder()
.setUid(this.getUid()) .setUid(this.getUid())
...@@ -671,22 +664,22 @@ public class GenshinPlayer { ...@@ -671,22 +664,22 @@ public class GenshinPlayer {
.setFinishAchievementNum(0); .setFinishAchievementNum(0);
return social; return social;
} }
public WorldPlayerLocationInfo getWorldPlayerLocationInfo() { public WorldPlayerLocationInfo getWorldPlayerLocationInfo() {
return WorldPlayerLocationInfo.newBuilder() return WorldPlayerLocationInfo.newBuilder()
.setSceneId(this.getSceneId()) .setSceneId(this.getSceneId())
.setPlayerLoc(this.getPlayerLocationInfo()) .setPlayerLoc(this.getPlayerLocationInfo())
.build(); .build();
} }
public PlayerLocationInfo getPlayerLocationInfo() { public PlayerLocationInfo getPlayerLocationInfo() {
return PlayerLocationInfo.newBuilder() return PlayerLocationInfo.newBuilder()
.setUid(this.getUid()) .setUid(this.getUid())
.setPos(this.getPos().toProto()) .setPos(this.getPos().toProto())
.setRot(this.getRotation().toProto()) .setRot(this.getRotation().toProto())
.build(); .build();
} }
public synchronized void onTick() { public synchronized void onTick() {
// Check ping // Check ping
if (this.getLastPingTime() > System.currentTimeMillis() + 60000) { if (this.getLastPingTime() > System.currentTimeMillis() + 60000) {
...@@ -706,7 +699,7 @@ public class GenshinPlayer { ...@@ -706,7 +699,7 @@ public class GenshinPlayer {
if (this.getWorld() != null) { if (this.getWorld() != null) {
// RTT notify - very important to send this often // RTT notify - very important to send this often
this.sendPacket(new PacketWorldPlayerRTTNotify(this.getWorld())); this.sendPacket(new PacketWorldPlayerRTTNotify(this.getWorld()));
// Update player locations if in multiplayer every 5 seconds // Update player locations if in multiplayer every 5 seconds
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
if (this.getWorld().isMultiplayer() && this.getScene() != null && time > nextSendPlayerLocTime) { if (this.getWorld().isMultiplayer() && this.getScene() != null && time > nextSendPlayerLocTime) {
...@@ -716,7 +709,7 @@ public class GenshinPlayer { ...@@ -716,7 +709,7 @@ public class GenshinPlayer {
} }
} }
} }
public void resetSendPlayerLocTime() { public void resetSendPlayerLocTime() {
this.nextSendPlayerLocTime = System.currentTimeMillis() + 5000; this.nextSendPlayerLocTime = System.currentTimeMillis() + 5000;
} }
...@@ -725,7 +718,7 @@ public class GenshinPlayer { ...@@ -725,7 +718,7 @@ public class GenshinPlayer {
private void onLoad() { private void onLoad() {
this.getTeamManager().setPlayer(this); this.getTeamManager().setPlayer(this);
} }
public void save() { public void save() {
DatabaseHelper.savePlayer(this); DatabaseHelper.savePlayer(this);
} }
...@@ -734,78 +727,80 @@ public class GenshinPlayer { ...@@ -734,78 +727,80 @@ public class GenshinPlayer {
// Make sure these exist // Make sure these exist
if (this.getTeamManager() == null) { if (this.getTeamManager() == null) {
this.teamManager = new TeamManager(this); this.teamManager = new TeamManager(this);
} if (this.getProfile().getUid() == 0) { }
if (this.getProfile().getUid() == 0) {
this.getProfile().syncWithCharacter(this); this.getProfile().syncWithCharacter(this);
} }
// Check if player object exists in server // Check if player object exists in server
// TODO - optimize // TODO - optimize
GenshinPlayer exists = this.getServer().getPlayerByUid(getUid()); GenshinPlayer exists = this.getServer().getPlayerByUid(getUid());
if (exists != null) { if (exists != null) {
exists.getSession().close(); exists.getSession().close();
} }
// Load from db // Load from db
this.getAvatars().loadFromDatabase(); this.getAvatars().loadFromDatabase();
this.getInventory().loadFromDatabase(); this.getInventory().loadFromDatabase();
this.getAvatars().postLoad(); this.getAvatars().postLoad();
this.getFriendsList().loadFromDatabase(); this.getFriendsList().loadFromDatabase();
// Create world // Create world
World world = new World(this); World world = new World(this);
world.addPlayer(this); world.addPlayer(this);
// Add to gameserver // Add to gameserver
if (getSession().isActive()) { if (getSession().isActive()) {
getServer().registerPlayer(this); getServer().registerPlayer(this);
getProfile().setPlayer(this); // Set online getProfile().setPlayer(this); // Set online
} }
// Multiplayer setting // Multiplayer setting
this.setProperty(PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE, this.getMpSetting().getNumber()); this.setProperty(PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE, this.getMpSetting().getNumber());
this.setProperty(PlayerProperty.PROP_IS_MP_MODE_AVAILABLE, 1); this.setProperty(PlayerProperty.PROP_IS_MP_MODE_AVAILABLE, 1);
// Packets // Packets
session.send(new PacketPlayerDataNotify(this)); // Player data session.send(new PacketPlayerDataNotify(this)); // Player data
session.send(new PacketStoreWeightLimitNotify()); session.send(new PacketStoreWeightLimitNotify());
session.send(new PacketPlayerStoreNotify(this)); session.send(new PacketPlayerStoreNotify(this));
session.send(new PacketAvatarDataNotify(this)); session.send(new PacketAvatarDataNotify(this));
session.send(new PacketPlayerEnterSceneNotify(this)); // Enter game world session.send(new PacketPlayerEnterSceneNotify(this)); // Enter game world
session.send(new PacketPlayerLevelRewardUpdateNotify(rewardedLevels));
session.send(new PacketOpenStateUpdateNotify()); session.send(new PacketOpenStateUpdateNotify());
// First notify packets sent // First notify packets sent
this.setHasSentAvatarDataNotify(true); this.setHasSentAvatarDataNotify(true);
} }
public void onLogout() { public void onLogout() {
// Leave world // Leave world
if (this.getWorld() != null) { if (this.getWorld() != null) {
this.getWorld().removePlayer(this); this.getWorld().removePlayer(this);
} }
// Status stuff // Status stuff
this.getProfile().syncWithCharacter(this); this.getProfile().syncWithCharacter(this);
this.getProfile().setPlayer(null); // Set offline this.getProfile().setPlayer(null); // Set offline
this.getCoopRequests().clear(); this.getCoopRequests().clear();
// Save to db // Save to db
this.save(); this.save();
this.getTeamManager().saveAvatars(); this.getTeamManager().saveAvatars();
this.getFriendsList().save(); this.getFriendsList().save();
} }
public enum SceneLoadState { public enum SceneLoadState {
NONE (0), LOADING (1), INIT (2), LOADED (3); NONE(0), LOADING(1), INIT(2), LOADED(3);
private final int value; private final int value;
private SceneLoadState(int value) { private SceneLoadState(int value) {
this.value = value; this.value = value;
} }
public int getValue() { public int getValue() {
return this.value; return this.value;
} }
......
...@@ -89,6 +89,12 @@ public class GenshinAvatar { ...@@ -89,6 +89,12 @@ public class GenshinAvatar {
private int flyCloak; private int flyCloak;
private int costume; private int costume;
private int bornTime; private int bornTime;
private int fetterLevel = 1;
private int fetterExp;
private int nameCardRewardId;
private int nameCardId;
public GenshinAvatar() { public GenshinAvatar() {
// Morhpia only! // Morhpia only!
...@@ -107,6 +113,8 @@ public class GenshinAvatar { ...@@ -107,6 +113,8 @@ public class GenshinAvatar {
public GenshinAvatar(AvatarData data) { public GenshinAvatar(AvatarData data) {
this(); this();
this.avatarId = data.getId(); this.avatarId = data.getId();
this.nameCardRewardId = data.getNameCardRewardId();
this.nameCardId = data.getNameCardId();
this.data = data; this.data = data;
this.bornTime = (int) (System.currentTimeMillis() / 1000); this.bornTime = (int) (System.currentTimeMillis() / 1000);
this.flyCloak = 140001; this.flyCloak = 140001;
...@@ -169,6 +177,14 @@ public class GenshinAvatar { ...@@ -169,6 +177,14 @@ public class GenshinAvatar {
this.satiation = satiation; this.satiation = satiation;
} }
public int getNameCardRewardId() {
return nameCardRewardId;
}
public void setNameCardRewardId(int nameCardRewardId) {
this.nameCardRewardId = nameCardRewardId;
}
public int getSatiationPenalty() { public int getSatiationPenalty() {
return satiationPenalty; return satiationPenalty;
} }
...@@ -281,6 +297,30 @@ public class GenshinAvatar { ...@@ -281,6 +297,30 @@ public class GenshinAvatar {
return fetters; return fetters;
} }
public int getFetterLevel() {
return fetterLevel;
}
public void setFetterLevel(int fetterLevel) {
this.fetterLevel = fetterLevel;
}
public int getFetterExp() {
return fetterExp;
}
public void setFetterExp(int fetterExp) {
this.fetterExp = fetterExp;
}
public int getNameCardId() {
return nameCardId;
}
public void setNameCardId(int nameCardId) {
this.nameCardId = nameCardId;
}
public float getCurrentHp() { public float getCurrentHp() {
return currentHp; return currentHp;
} }
...@@ -403,6 +443,8 @@ public class GenshinAvatar { ...@@ -403,6 +443,8 @@ public class GenshinAvatar {
// Fetters // Fetters
this.setFetterList(data.getFetters()); this.setFetterList(data.getFetters());
this.setNameCardRewardId(data.getNameCardRewardId());
this.setNameCardId(data.getNameCardId());
// Get hp percent, set to 100% if none // Get hp percent, set to 100% if none
float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
...@@ -701,9 +743,14 @@ public class GenshinAvatar { ...@@ -701,9 +743,14 @@ public class GenshinAvatar {
} }
public AvatarInfo toProto() { public AvatarInfo toProto() {
int fetterLevel = this.getFetterLevel();
AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder() AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder()
.setExpLevel(10) .setExpLevel(fetterLevel);
.setExpNumber(6325); // Highest Level
if (fetterLevel != 10) {
avatarFetter.setExpNumber(this.getFetterExp());
}
if (this.getFetterList() != null) { if (this.getFetterList() != null) {
for (int i = 0; i < this.getFetterList().size(); i++) { for (int i = 0; i < this.getFetterList().size(); i++) {
...@@ -715,6 +762,12 @@ public class GenshinAvatar { ...@@ -715,6 +762,12 @@ public class GenshinAvatar {
} }
} }
int cardId = this.getNameCardId();
if (this.getPlayer().getNameCardList().contains(cardId)) {
avatarFetter.addRewardedFetterLevelList(10);
}
AvatarInfo.Builder avatarInfo = AvatarInfo.newBuilder() AvatarInfo.Builder avatarInfo = AvatarInfo.newBuilder()
.setAvatarId(this.getAvatarId()) .setAvatarId(this.getAvatarId())
.setGuid(this.getGuid()) .setGuid(this.getGuid())
......
...@@ -90,7 +90,7 @@ public class GenshinItem { ...@@ -90,7 +90,7 @@ public class GenshinItem {
// Equip data // Equip data
if (getItemType() == ItemType.ITEM_WEAPON) { if (getItemType() == ItemType.ITEM_WEAPON) {
this.level = 1; this.level = this.count > 1 ? this.count : 1;
this.affixes = new ArrayList<>(2); this.affixes = new ArrayList<>(2);
if (getItemData().getSkillAffix() != null) { if (getItemData().getSkillAffix() != null) {
for (int skillAffix : getItemData().getSkillAffix()) { for (int skillAffix : getItemData().getSkillAffix()) {
......
...@@ -711,6 +711,31 @@ public class InventoryManager { ...@@ -711,6 +711,31 @@ public class InventoryManager {
player.sendPacket(new PacketAvatarUpgradeRsp(avatar, oldLevel, oldPropMap)); player.sendPacket(new PacketAvatarUpgradeRsp(avatar, oldLevel, oldPropMap));
} }
public void upgradeAvatarFetterLevel(GenshinPlayer player, GenshinAvatar avatar, int expGain) {
// May work. Not test.
int maxLevel = 10; // Keep it until I think of a more "elegant" way
int level = avatar.getFetterLevel();
int exp = avatar.getFetterExp();
int reqExp = GenshinData.getAvatarFetterLevelExpRequired(level);
while (expGain > 0 && reqExp > 0 && level < maxLevel) {
int toGain = Math.min(expGain, reqExp - exp);
exp += toGain;
expGain -= toGain;
if (exp >= reqExp) {
exp = 0;
level += 1;
reqExp = GenshinData.getAvatarFetterLevelExpRequired(level);
}
}
avatar.setFetterLevel(level);
avatar.setFetterExp(exp);
avatar.save();
player.sendPacket(new PacketAvatarPropNotify(avatar));
}
public void upgradeAvatarSkill(GenshinPlayer player, long guid, int skillId) { public void upgradeAvatarSkill(GenshinPlayer player, long guid, int skillId) {
// Sanity checks // Sanity checks
GenshinAvatar avatar = player.getAvatars().getAvatarByGuid(guid); GenshinAvatar avatar = player.getAvatars().getAvatarByGuid(guid);
......
package emu.grasscutter.game.player; package emu.grasscutter.game.player;
import dev.morphia.annotations.Entity;
import emu.grasscutter.net.proto.BirthdayOuterClass.Birthday; import emu.grasscutter.net.proto.BirthdayOuterClass.Birthday;
@Entity
public class PlayerBirthday { public class PlayerBirthday {
private int day; private int day;
private int month; private int month;
......
...@@ -64,9 +64,8 @@ public class MihoyoKcpServer extends Thread { ...@@ -64,9 +64,8 @@ public class MihoyoKcpServer extends Thread {
// Wait until the server socket is closed. // Wait until the server socket is closed.
f.channel().closeFuture().sync(); f.channel().closeFuture().sync();
} catch (Exception e) { } catch (Exception exception) {
// TODO Auto-generated catch block Grasscutter.getLogger().error("Unable to start game server.", exception);
e.printStackTrace();
} finally { } finally {
// Close // Close
finish(); finish();
......
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.data.GenshinData;
import emu.grasscutter.data.def.RewardData;
import emu.grasscutter.game.avatar.GenshinAvatar;
import emu.grasscutter.game.inventory.GenshinItem;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.AvatarFetterLevelRewardReqOuterClass.AvatarFetterLevelRewardReq;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketAvatarDataNotify;
import emu.grasscutter.server.packet.send.PacketAvatarFetterDataNotify;
import emu.grasscutter.server.packet.send.PacketAvatarFetterLevelRewardRsp;
import emu.grasscutter.server.packet.send.PacketItemAddHintNotify;
import emu.grasscutter.server.packet.send.PacketUnlockNameCardNotify;
import emu.grasscutter.net.packet.PacketHandler;
@Opcodes(PacketOpcodes.AvatarFetterLevelRewardReq)
public class HandlerAvatarFetterLevelRewardReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
AvatarFetterLevelRewardReq req = AvatarFetterLevelRewardReq.parseFrom(payload);
if (req.getFetterLevel() < 10) {
// You don't have a full level of fetter level, why do you want to get a divorce certificate?
session.send(new PacketAvatarFetterLevelRewardRsp(req.getAvatarGuid(), req.getFetterLevel()));
} else {
long avatarGuid = req.getAvatarGuid();
GenshinAvatar avatar = session
.getPlayer()
.getAvatars()
.getAvatarByGuid(avatarGuid);
int rewardId = avatar.getNameCardRewardId();
RewardData card = GenshinData.getRewardDataMap().get(rewardId);
int cardId = card.getRewardItemList().get(0).getItemId();
if (session.getPlayer().getNameCardList().contains(cardId)) {
// Already got divorce certificate.
session.getPlayer().sendPacket(new PacketAvatarFetterLevelRewardRsp(req.getAvatarGuid(), req.getFetterLevel(), rewardId));
return;
}
GenshinItem item = new GenshinItem(cardId);
session.getPlayer().getInventory().addItem(item);
session.getPlayer().sendPacket(new PacketItemAddHintNotify(item, ActionReason.FetterLevelReward));
session.getPlayer().sendPacket(new PacketUnlockNameCardNotify(cardId));
session.send(new PacketAvatarFetterDataNotify(avatar));
session.send(new PacketAvatarDataNotify(avatar.getPlayer()));
session.send(new PacketAvatarFetterLevelRewardRsp(avatarGuid, req.getFetterLevel(), rewardId));
}
}
}
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