2022-04-17 05:43:07 -07:00
package emu.grasscutter.game ;
2022-04-25 14:30:56 +08:00
import java.time.Instant ;
import java.util.* ;
2022-04-17 05:43:07 -07:00
import dev.morphia.annotations.* ;
import emu.grasscutter.GenshinConstants ;
import emu.grasscutter.Grasscutter ;
2022-04-25 21:53:10 +08:00
import emu.grasscutter.command.CommandHandler ;
2022-04-17 05:43:07 -07:00
import emu.grasscutter.data.GenshinData ;
import emu.grasscutter.data.def.PlayerLevelData ;
import emu.grasscutter.database.DatabaseHelper ;
import emu.grasscutter.game.avatar.AvatarProfileData ;
import emu.grasscutter.game.avatar.AvatarStorage ;
import emu.grasscutter.game.avatar.GenshinAvatar ;
import emu.grasscutter.game.entity.EntityItem ;
import emu.grasscutter.game.entity.GenshinEntity ;
import emu.grasscutter.game.friends.FriendsList ;
import emu.grasscutter.game.friends.PlayerProfile ;
import emu.grasscutter.game.gacha.PlayerGachaInfo ;
import emu.grasscutter.game.inventory.GenshinItem ;
import emu.grasscutter.game.inventory.Inventory ;
2022-04-23 03:22:32 +02:00
import emu.grasscutter.game.player.PlayerBirthday ;
2022-04-17 05:43:07 -07:00
import emu.grasscutter.game.props.ActionReason ;
import emu.grasscutter.game.props.PlayerProperty ;
import emu.grasscutter.net.packet.GenshinPacket ;
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry ;
import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry ;
import emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage ;
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType ;
import emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType ;
import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo ;
import emu.grasscutter.net.proto.PlayerApplyEnterMpReasonOuterClass.PlayerApplyEnterMpReason ;
import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo ;
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail ;
2022-04-20 18:44:02 -07:00
import emu.grasscutter.net.proto.WorldPlayerLocationInfoOuterClass.WorldPlayerLocationInfo ;
2022-04-17 05:43:07 -07:00
import emu.grasscutter.server.game.GameServer ;
import emu.grasscutter.server.game.GameSession ;
import emu.grasscutter.server.packet.send.PacketAbilityInvocationsNotify ;
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 ;
2022-04-20 03:42:59 -07:00
import emu.grasscutter.server.packet.send.PacketClientAbilityInitFinishNotify ;
2022-04-17 05:43:07 -07:00
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 ;
2022-04-20 18:44:02 -07:00
import emu.grasscutter.server.packet.send.PacketScenePlayerLocationNotify ;
2022-04-24 13:22:26 +08:00
import emu.grasscutter.server.packet.send.PacketPlayerLevelRewardUpdateNotify ;
2022-04-17 05:43:07 -07:00
import emu.grasscutter.server.packet.send.PacketSetNameCardRsp ;
import emu.grasscutter.server.packet.send.PacketStoreWeightLimitNotify ;
import emu.grasscutter.server.packet.send.PacketUnlockNameCardNotify ;
2022-04-20 18:44:02 -07:00
import emu.grasscutter.server.packet.send.PacketWorldPlayerLocationNotify ;
2022-04-17 05:43:07 -07:00
import emu.grasscutter.server.packet.send.PacketWorldPlayerRTTNotify ;
2022-04-24 18:01:32 +08:00
import emu.grasscutter.server.packet.send.PacketMailChangeNotify ;
2022-04-17 05:43:07 -07:00
import emu.grasscutter.utils.Position ;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap ;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap ;
2022-04-25 14:51:34 +08:00
import java.util.* ;
2022-04-20 21:11:57 -04:00
@Entity ( value = " players " , useDiscriminator = false )
2022-04-17 05:43:07 -07:00
public class GenshinPlayer {
@Id private int id ;
@Indexed ( options = @IndexOptions ( unique = true ) ) private String accountId ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
@Transient private Account account ;
private String nickname ;
private String signature ;
private int headImage ;
private int nameCardId = 210001 ;
private Position pos ;
private Position rotation ;
2022-04-23 03:22:32 +02:00
private PlayerBirthday birthday ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
private Map < Integer , Integer > properties ;
private Set < Integer > nameCardList ;
private Set < Integer > flyCloakList ;
private Set < Integer > costumeList ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
@Transient private long nextGuid = 0 ;
@Transient private int peerId ;
@Transient private World world ;
2022-04-18 09:39:29 -07:00
@Transient private GenshinScene scene ;
2022-04-17 05:43:07 -07:00
@Transient private GameSession session ;
@Transient private AvatarStorage avatars ;
@Transient private Inventory inventory ;
@Transient private FriendsList friendsList ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
private TeamManager teamManager ;
private PlayerGachaInfo gachaInfo ;
private PlayerProfile playerProfile ;
private MpSettingType mpSetting = MpSettingType . MpSettingEnterAfterApply ;
private boolean showAvatar ;
private ArrayList < AvatarProfileData > shownAvatars ;
2022-04-24 13:22:26 +08:00
private Set < Integer > rewardedLevels ;
2022-04-23 23:07:18 +08:00
private ArrayList < Mail > mail ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
private int sceneId ;
private int regionId ;
private int mainCharacterId ;
private boolean godmode ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
@Transient private boolean paused ;
@Transient private int enterSceneToken ;
@Transient private SceneLoadState sceneState ;
@Transient private boolean hasSentAvatarDataNotify ;
2022-04-20 18:44:02 -07:00
@Transient private long nextSendPlayerLocTime = 0 ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
@Transient private final Int2ObjectMap < CoopRequest > coopRequests ;
@Transient private final InvokeHandler < CombatInvokeEntry > combatInvokeHandler ;
@Transient private final InvokeHandler < AbilityInvokeEntry > abilityInvokeHandler ;
2022-04-20 03:42:59 -07:00
@Transient private final InvokeHandler < AbilityInvokeEntry > clientAbilityInitFinishHandler ;
2022-04-25 14:51:34 +08:00
@Deprecated
@SuppressWarnings ( { " rawtypes " , " unchecked " } ) // Morphia only!
public GenshinPlayer ( ) {
2022-04-17 05:43:07 -07:00
this . inventory = new Inventory ( this ) ;
this . avatars = new AvatarStorage ( this ) ;
this . friendsList = new FriendsList ( this ) ;
this . pos = new Position ( ) ;
this . rotation = new Position ( ) ;
this . properties = new HashMap < > ( ) ;
for ( PlayerProperty prop : PlayerProperty . values ( ) ) {
if ( prop . getId ( ) < 10000 ) {
continue ;
}
this . properties . put ( prop . getId ( ) , 0 ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-20 18:48:26 -07:00
this . gachaInfo = new PlayerGachaInfo ( ) ;
this . nameCardList = new HashSet < > ( ) ;
this . flyCloakList = new HashSet < > ( ) ;
this . costumeList = new HashSet < > ( ) ;
2022-04-25 14:51:34 +08:00
2022-04-23 23:07:18 +08:00
this . mail = new ArrayList < > ( ) ;
2022-04-17 05:43:07 -07:00
this . setSceneId ( 3 ) ;
this . setRegionId ( 1 ) ;
this . sceneState = SceneLoadState . NONE ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
this . coopRequests = new Int2ObjectOpenHashMap < > ( ) ;
this . combatInvokeHandler = new InvokeHandler ( PacketCombatInvocationsNotify . class ) ;
this . abilityInvokeHandler = new InvokeHandler ( PacketAbilityInvocationsNotify . class ) ;
2022-04-20 03:42:59 -07:00
this . clientAbilityInitFinishHandler = new InvokeHandler ( PacketClientAbilityInitFinishNotify . class ) ;
2022-04-23 03:22:32 +02:00
this . birthday = new PlayerBirthday ( ) ;
2022-04-24 13:22:26 +08:00
this . rewardedLevels = new HashSet < > ( ) ;
2022-04-17 05:43:07 -07:00
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// On player creation
public GenshinPlayer ( GameSession session ) {
this ( ) ;
this . account = session . getAccount ( ) ;
this . accountId = this . getAccount ( ) . getId ( ) ;
this . session = session ;
this . nickname = " Traveler " ;
this . signature = " " ;
this . teamManager = new TeamManager ( this ) ;
2022-04-23 03:22:32 +02:00
this . birthday = new PlayerBirthday ( ) ;
2022-04-17 05:43:07 -07:00
this . setProperty ( PlayerProperty . PROP_PLAYER_LEVEL , 1 ) ;
this . setProperty ( PlayerProperty . PROP_IS_SPRING_AUTO_USE , 1 ) ;
this . setProperty ( PlayerProperty . PROP_SPRING_AUTO_USE_PERCENT , 50 ) ;
this . setProperty ( PlayerProperty . PROP_IS_FLYABLE , 1 ) ;
this . setProperty ( PlayerProperty . PROP_IS_TRANSFERABLE , 1 ) ;
this . setProperty ( PlayerProperty . PROP_MAX_STAMINA , 24000 ) ;
this . setProperty ( PlayerProperty . PROP_CUR_PERSIST_STAMINA , 24000 ) ;
this . setProperty ( PlayerProperty . PROP_PLAYER_RESIN , 160 ) ;
this . getFlyCloakList ( ) . add ( 140001 ) ;
this . getNameCardList ( ) . add ( 210001 ) ;
this . getPos ( ) . set ( GenshinConstants . START_POSITION ) ;
this . getRotation ( ) . set ( 0 , 307 , 0 ) ;
}
2022-04-19 02:22:21 -07:00
public int getUid ( ) {
2022-04-17 05:43:07 -07:00
return id ;
}
2022-04-19 02:22:21 -07:00
public void setUid ( int id ) {
2022-04-17 05:43:07 -07:00
this . id = id ;
}
2022-04-25 14:51:34 +08:00
2022-04-19 02:22:21 -07:00
public long getNextGenshinGuid ( ) {
2022-04-17 05:43:07 -07:00
long nextId = + + this . nextGuid ;
2022-04-19 02:22:21 -07:00
return ( ( long ) this . getUid ( ) < < 32 ) + nextId ;
2022-04-17 05:43:07 -07:00
}
public Account getAccount ( ) {
return account ;
}
public void setAccount ( Account account ) {
this . account = account ;
2022-04-19 02:22:21 -07:00
this . account . setPlayerId ( getUid ( ) ) ;
2022-04-17 05:43:07 -07:00
}
public GameSession getSession ( ) {
return session ;
}
public void setSession ( GameSession session ) {
this . session = session ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public boolean isOnline ( ) {
return this . getSession ( ) ! = null & & this . getSession ( ) . isActive ( ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public GameServer getServer ( ) {
return this . getSession ( ) . getServer ( ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public synchronized World getWorld ( ) {
return this . world ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public synchronized void setWorld ( World world ) {
this . world = world ;
}
2022-04-25 14:51:34 +08:00
2022-04-18 09:39:29 -07:00
public GenshinScene getScene ( ) {
return scene ;
}
public void setScene ( GenshinScene scene ) {
this . scene = scene ;
}
2022-04-17 05:43:07 -07:00
public int getGmLevel ( ) {
return 1 ;
}
public String getNickname ( ) {
return nickname ;
}
public void setNickname ( String nickName ) {
this . nickname = nickName ;
this . updateProfile ( ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public int getHeadImage ( ) {
return headImage ;
}
public void setHeadImage ( int picture ) {
this . headImage = picture ;
this . updateProfile ( ) ;
}
public String getSignature ( ) {
return signature ;
}
public void setSignature ( String signature ) {
this . signature = signature ;
this . updateProfile ( ) ;
}
public Position getPos ( ) {
return pos ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public Position getRotation ( ) {
return rotation ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public int getLevel ( ) {
return this . getProperty ( PlayerProperty . PROP_PLAYER_LEVEL ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public int getExp ( ) {
return this . getProperty ( PlayerProperty . PROP_PLAYER_EXP ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public int getWorldLevel ( ) {
return this . getProperty ( PlayerProperty . PROP_PLAYER_WORLD_LEVEL ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public int getPrimogems ( ) {
return this . getProperty ( PlayerProperty . PROP_PLAYER_HCOIN ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void setPrimogems ( int primogem ) {
this . setProperty ( PlayerProperty . PROP_PLAYER_HCOIN , primogem ) ;
this . sendPacket ( new PacketPlayerPropNotify ( this , PlayerProperty . PROP_PLAYER_HCOIN ) ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public int getMora ( ) {
return this . getProperty ( PlayerProperty . PROP_PLAYER_SCOIN ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void setMora ( int mora ) {
this . setProperty ( PlayerProperty . PROP_PLAYER_SCOIN , mora ) ;
this . sendPacket ( new PacketPlayerPropNotify ( this , PlayerProperty . PROP_PLAYER_SCOIN ) ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
private int getExpRequired ( int level ) {
PlayerLevelData levelData = GenshinData . getPlayerLevelDataMap ( ) . get ( level ) ;
2022-04-25 14:51:34 +08:00
return levelData ! = null ? levelData . getExp ( ) : 0 ;
2022-04-17 05:43:07 -07:00
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
private float getExpModifier ( ) {
2022-04-21 13:53:50 +08:00
return Grasscutter . getConfig ( ) . getGameServerOptions ( ) . getGameRates ( ) . ADVENTURE_EXP_RATE ;
2022-04-17 05:43:07 -07:00
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Affected by exp rate
public void earnExp ( int exp ) {
addExpDirectly ( ( int ) ( exp * getExpModifier ( ) ) ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Directly give player exp
public void addExpDirectly ( int gain ) {
boolean hasLeveledUp = false ;
int level = getLevel ( ) ;
int exp = getExp ( ) ;
int reqExp = getExpRequired ( level ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
exp + = gain ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
while ( exp > = reqExp & & reqExp > 0 ) {
exp - = reqExp ;
level + = 1 ;
reqExp = getExpRequired ( level ) ;
hasLeveledUp = true ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
if ( hasLeveledUp ) {
// Set level property
this . setProperty ( PlayerProperty . PROP_PLAYER_LEVEL , level ) ;
// Update social status
this . updateProfile ( ) ;
// Update player with packet
this . sendPacket ( new PacketPlayerPropNotify ( this , PlayerProperty . PROP_PLAYER_LEVEL ) ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Set exp
this . setProperty ( PlayerProperty . PROP_PLAYER_EXP , exp ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Update player with packet
this . sendPacket ( new PacketPlayerPropNotify ( this , PlayerProperty . PROP_PLAYER_EXP ) ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
private void updateProfile ( ) {
getProfile ( ) . syncWithCharacter ( this ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public boolean isFirstLoginEnterScene ( ) {
return ! this . hasSentAvatarDataNotify ;
}
public TeamManager getTeamManager ( ) {
return this . teamManager ;
}
public PlayerGachaInfo getGachaInfo ( ) {
return gachaInfo ;
}
public PlayerProfile getProfile ( ) {
if ( this . playerProfile = = null ) {
this . playerProfile = new PlayerProfile ( this ) ;
}
return playerProfile ;
}
public Map < Integer , Integer > getProperties ( ) {
return properties ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void setProperty ( PlayerProperty prop , int value ) {
getProperties ( ) . put ( prop . getId ( ) , value ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public int getProperty ( PlayerProperty prop ) {
return getProperties ( ) . get ( prop . getId ( ) ) ;
}
public Set < Integer > getFlyCloakList ( ) {
return flyCloakList ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public Set < Integer > getCostumeList ( ) {
return costumeList ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public Set < Integer > getNameCardList ( ) {
return this . nameCardList ;
}
public MpSettingType getMpSetting ( ) {
return mpSetting ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public synchronized Int2ObjectMap < CoopRequest > getCoopRequests ( ) {
return coopRequests ;
}
public InvokeHandler < CombatInvokeEntry > getCombatInvokeHandler ( ) {
return this . combatInvokeHandler ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public InvokeHandler < AbilityInvokeEntry > getAbilityInvokeHandler ( ) {
return this . abilityInvokeHandler ;
}
2022-04-20 03:42:59 -07:00
public InvokeHandler < AbilityInvokeEntry > getClientAbilityInitFinishHandler ( ) {
return clientAbilityInitFinishHandler ;
}
2022-04-17 05:43:07 -07:00
public void setMpSetting ( MpSettingType mpSetting ) {
this . mpSetting = mpSetting ;
}
public AvatarStorage getAvatars ( ) {
return avatars ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public Inventory getInventory ( ) {
return inventory ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public FriendsList getFriendsList ( ) {
return this . friendsList ;
}
public int getEnterSceneToken ( ) {
return enterSceneToken ;
}
public void setEnterSceneToken ( int enterSceneToken ) {
this . enterSceneToken = enterSceneToken ;
}
public int getNameCardId ( ) {
return nameCardId ;
}
public void setNameCardId ( int nameCardId ) {
this . nameCardId = nameCardId ;
this . updateProfile ( ) ;
}
public int getMainCharacterId ( ) {
return mainCharacterId ;
}
public void setMainCharacterId ( int mainCharacterId ) {
this . mainCharacterId = mainCharacterId ;
}
public int getPeerId ( ) {
return peerId ;
}
public void setPeerId ( int peerId ) {
this . peerId = peerId ;
}
public int getClientTime ( ) {
return session . getClientTime ( ) ;
}
public long getLastPingTime ( ) {
return session . getLastPingTime ( ) ;
}
public boolean isPaused ( ) {
return paused ;
}
public void setPaused ( boolean newPauseState ) {
boolean oldPauseState = this . paused ;
this . paused = newPauseState ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
if ( newPauseState & & ! oldPauseState ) {
this . onPause ( ) ;
} else if ( oldPauseState & & ! newPauseState ) {
this . onUnpause ( ) ;
}
}
public SceneLoadState getSceneLoadState ( ) {
return sceneState ;
}
public void setSceneLoadState ( SceneLoadState sceneState ) {
this . sceneState = sceneState ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public boolean isInMultiplayer ( ) {
return this . getWorld ( ) ! = null & & this . getWorld ( ) . isMultiplayer ( ) ;
}
public int getSceneId ( ) {
return sceneId ;
}
public void setSceneId ( int sceneId ) {
this . sceneId = sceneId ;
}
public int getRegionId ( ) {
return regionId ;
}
public void setRegionId ( int regionId ) {
this . regionId = regionId ;
}
2022-04-25 14:51:34 +08:00
2022-04-18 22:10:41 -04:00
public boolean inGodmode ( ) {
2022-04-17 05:43:07 -07:00
return godmode ;
}
public void setGodmode ( boolean godmode ) {
this . godmode = godmode ;
}
public boolean hasSentAvatarDataNotify ( ) {
return hasSentAvatarDataNotify ;
}
public void setHasSentAvatarDataNotify ( boolean hasSentAvatarDataNotify ) {
this . hasSentAvatarDataNotify = hasSentAvatarDataNotify ;
}
public void addAvatar ( GenshinAvatar avatar ) {
boolean result = getAvatars ( ) . addAvatar ( avatar ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
if ( result ) {
// Add starting weapon
getAvatars ( ) . addStartingWeapon ( avatar ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Try adding to team if possible
//List<EntityAvatar> currentTeam = this.getTeamManager().getCurrentTeam();
boolean addedToTeam = false ;
/ *
if ( currentTeam . size ( ) < = GenshinConstants . MAX_AVATARS_IN_TEAM ) {
addedToTeam = currentTeam
}
* /
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Done
if ( hasSentAvatarDataNotify ( ) ) {
// Recalc stats
avatar . recalcStats ( ) ;
// Packet
sendPacket ( new PacketAvatarAddNotify ( avatar , addedToTeam ) ) ;
}
} else {
// Failed adding avatar
}
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void addFlycloak ( int flycloakId ) {
this . getFlyCloakList ( ) . add ( flycloakId ) ;
this . sendPacket ( new PacketAvatarGainFlycloakNotify ( flycloakId ) ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void addCostume ( int costumeId ) {
this . getCostumeList ( ) . add ( costumeId ) ;
this . sendPacket ( new PacketAvatarGainCostumeNotify ( costumeId ) ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void addNameCard ( int nameCardId ) {
this . getNameCardList ( ) . add ( nameCardId ) ;
this . sendPacket ( new PacketUnlockNameCardNotify ( nameCardId ) ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void setNameCard ( int nameCardId ) {
if ( ! this . getNameCardList ( ) . contains ( nameCardId ) ) {
return ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
this . setNameCardId ( nameCardId ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
this . sendPacket ( new PacketSetNameCardRsp ( nameCardId ) ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void dropMessage ( Object message ) {
2022-04-19 02:22:21 -07:00
this . sendPacket ( new PacketPrivateChatNotify ( GenshinConstants . SERVER_CONSOLE_UID , getUid ( ) , message . toString ( ) ) ) ;
2022-04-17 05:43:07 -07:00
}
2022-04-18 21:35:01 -07:00
/ * *
* Sends a message to another player .
2022-04-25 14:51:34 +08:00
*
* @param sender The sender of the message .
2022-04-18 21:35:01 -07:00
* @param message The message to send .
* /
public void sendMessage ( GenshinPlayer sender , Object message ) {
2022-04-19 02:22:21 -07:00
this . sendPacket ( new PacketPrivateChatNotify ( sender . getUid ( ) , this . getUid ( ) , message . toString ( ) ) ) ;
2022-04-17 05:43:07 -07:00
}
2022-04-25 14:51:34 +08:00
2022-04-25 13:51:19 +08:00
// ---------------------MAIL------------------------
2022-04-23 23:07:18 +08:00
2022-04-25 13:51:19 +08:00
public List < Mail > getAllMail ( ) { return this . mail ; }
2022-04-23 23:07:18 +08:00
2022-04-25 13:51:19 +08:00
public void sendMail ( Mail message ) {
2022-04-23 23:07:18 +08:00
message . _id = this . mail . size ( ) + 1 ;
2022-04-25 21:53:10 +08:00
this . mail . add ( message ) ;
2022-04-23 23:07:18 +08:00
this . save ( ) ;
2022-04-25 21:53:10 +08:00
Grasscutter . getLogger ( ) . info ( " Message sent to user [ " + this . getUid ( ) + " : " + this . getNickname ( ) + " ]! " ) ;
if ( this . getSession ( ) ! = null ) {
this . sendPacket ( new PacketMailChangeNotify ( this , message ) ) ;
} // TODO: setup a way for the mail notification to show up when someone receives mail when they were offline
2022-04-23 23:07:18 +08:00
}
2022-04-25 13:51:19 +08:00
public boolean deleteMail ( int mailId ) {
Mail message = getMailById ( mailId ) ;
if ( message ! = null ) {
2022-04-25 14:30:56 +08:00
int index = getMailIndex ( message ) ;
message . expireTime = ( int ) Instant . now ( ) . getEpochSecond ( ) ; // Just set the mail as expired for now. I don't want to implement a counter specifically for an account...
this . replaceMailByIndex ( index , message ) ;
2022-04-25 13:51:19 +08:00
return true ;
}
return false ;
}
public Mail getMailById ( int mailId ) {
return this . mail . stream ( ) . filter ( message - > message . _id = = mailId ) . findFirst ( ) . orElse ( null ) ;
}
public int getMailIndex ( Mail message ) {
return this . mail . indexOf ( message ) ;
}
2022-04-25 14:30:56 +08:00
public boolean replaceMailByIndex ( int index , Mail message ) {
if ( getMailById ( index ) ! = null ) {
this . mail . set ( index , message ) ;
this . save ( ) ;
2022-04-25 13:51:19 +08:00
return true ;
} else {
return false ;
}
}
2022-04-23 23:07:18 +08:00
2022-04-17 05:43:07 -07:00
public void interactWith ( int gadgetEntityId ) {
2022-04-18 09:39:29 -07:00
GenshinEntity entity = getScene ( ) . getEntityById ( gadgetEntityId ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
if ( entity = = null ) {
return ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Delete
2022-04-18 09:39:29 -07:00
entity . getScene ( ) . removeEntity ( entity ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Handle
if ( entity instanceof EntityItem ) {
// Pick item
EntityItem drop = ( EntityItem ) entity ;
GenshinItem item = new GenshinItem ( drop . getItemData ( ) , drop . getCount ( ) ) ;
// Add to inventory
boolean success = getInventory ( ) . addItem ( item ) ;
if ( success ) {
this . sendPacket ( new PacketGadgetInteractRsp ( drop , InteractType . InteractPickItem ) ) ;
this . sendPacket ( new PacketItemAddHintNotify ( item , ActionReason . SubfieldDrop ) ) ;
}
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
return ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void onPause ( ) {
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void onUnpause ( ) {
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void sendPacket ( GenshinPacket packet ) {
if ( this . hasSentAvatarDataNotify ) {
this . getSession ( ) . send ( packet ) ;
}
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public OnlinePlayerInfo getOnlinePlayerInfo ( ) {
OnlinePlayerInfo . Builder onlineInfo = OnlinePlayerInfo . newBuilder ( )
2022-04-25 15:16:18 +08:00
. setUid ( this . getUid ( ) )
. setNickname ( this . getNickname ( ) )
. setPlayerLevel ( this . getLevel ( ) )
. setMpSettingType ( this . getMpSetting ( ) )
. setNameCardId ( this . getNameCardId ( ) )
. setSignature ( this . getSignature ( ) )
. setAvatar ( HeadImage . newBuilder ( ) . setAvatarId ( this . getHeadImage ( ) ) ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
if ( this . getWorld ( ) ! = null ) {
onlineInfo . setCurPlayerNumInWorld ( this . getWorld ( ) . getPlayers ( ) . indexOf ( this ) + 1 ) ;
} else {
onlineInfo . setCurPlayerNumInWorld ( 1 ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
return onlineInfo . build ( ) ;
}
2022-04-25 14:51:34 +08:00
public PlayerBirthday getBirthday ( ) {
2022-04-23 03:22:32 +02:00
return this . birthday ;
}
public void setBirthday ( int d , int m ) {
this . birthday = new PlayerBirthday ( d , m ) ;
this . updateProfile ( ) ;
}
2022-04-25 14:51:34 +08:00
public boolean hasBirthday ( ) {
return this . birthday . getDay ( ) > 0 ;
}
2022-04-24 13:22:26 +08:00
public Set < Integer > getRewardedLevels ( ) {
return rewardedLevels ;
}
public void setRewardedLevels ( Set < Integer > rewardedLevels ) {
this . rewardedLevels = rewardedLevels ;
}
2022-04-17 05:43:07 -07:00
public SocialDetail . Builder getSocialDetail ( ) {
2022-04-25 15:16:18 +08:00
SocialDetail . Builder social = SocialDetail . newBuilder ( )
. setUid ( this . getUid ( ) )
. setAvatar ( HeadImage . newBuilder ( ) . setAvatarId ( this . getHeadImage ( ) ) )
. setNickname ( this . getNickname ( ) )
. setSignature ( this . getSignature ( ) )
. setLevel ( this . getLevel ( ) )
. setBirthday ( this . getBirthday ( ) . getFilledProtoWhenNotEmpty ( ) )
. setWorldLevel ( this . getWorldLevel ( ) )
. setUnk1 ( 1 )
. setUnk3 ( 1 )
. setNameCardId ( this . getNameCardId ( ) )
. setFinishAchievementNum ( 0 ) ;
2022-04-17 05:43:07 -07:00
return social ;
}
2022-04-25 14:51:34 +08:00
2022-04-20 18:44:02 -07:00
public WorldPlayerLocationInfo getWorldPlayerLocationInfo ( ) {
2022-04-25 15:16:18 +08:00
return WorldPlayerLocationInfo . newBuilder ( )
. setSceneId ( this . getSceneId ( ) )
. setPlayerLoc ( this . getPlayerLocationInfo ( ) )
. build ( ) ;
2022-04-20 18:44:02 -07:00
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public PlayerLocationInfo getPlayerLocationInfo ( ) {
2022-04-25 15:16:18 +08:00
return PlayerLocationInfo . newBuilder ( )
. setUid ( this . getUid ( ) )
. setPos ( this . getPos ( ) . toProto ( ) )
. setRot ( this . getRotation ( ) . toProto ( ) )
. build ( ) ;
2022-04-17 05:43:07 -07:00
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public synchronized void onTick ( ) {
// Check ping
if ( this . getLastPingTime ( ) > System . currentTimeMillis ( ) + 60000 ) {
this . getSession ( ) . close ( ) ;
return ;
}
// Check co-op requests
Iterator < CoopRequest > it = this . getCoopRequests ( ) . values ( ) . iterator ( ) ;
while ( it . hasNext ( ) ) {
CoopRequest req = it . next ( ) ;
if ( req . isExpired ( ) ) {
req . getRequester ( ) . sendPacket ( new PacketPlayerApplyEnterMpResultNotify ( this , false , PlayerApplyEnterMpReason . SystemJudge ) ) ;
it . remove ( ) ;
}
}
// Ping
if ( this . getWorld ( ) ! = null ) {
2022-04-20 18:44:02 -07:00
// RTT notify - very important to send this often
this . sendPacket ( new PacketWorldPlayerRTTNotify ( this . getWorld ( ) ) ) ;
2022-04-25 14:51:34 +08:00
2022-04-20 18:44:02 -07:00
// Update player locations if in multiplayer every 5 seconds
long time = System . currentTimeMillis ( ) ;
if ( this . getWorld ( ) . isMultiplayer ( ) & & this . getScene ( ) ! = null & & time > nextSendPlayerLocTime ) {
this . sendPacket ( new PacketWorldPlayerLocationNotify ( this . getWorld ( ) ) ) ;
this . sendPacket ( new PacketScenePlayerLocationNotify ( this . getScene ( ) ) ) ;
this . resetSendPlayerLocTime ( ) ;
}
2022-04-17 05:43:07 -07:00
}
}
2022-04-25 14:51:34 +08:00
2022-04-20 18:44:02 -07:00
public void resetSendPlayerLocTime ( ) {
this . nextSendPlayerLocTime = System . currentTimeMillis ( ) + 5000 ;
}
2022-04-17 05:43:07 -07:00
@PostLoad
private void onLoad ( ) {
this . getTeamManager ( ) . setPlayer ( this ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void save ( ) {
DatabaseHelper . savePlayer ( this ) ;
}
public void onLogin ( ) {
// Make sure these exist
if ( this . getTeamManager ( ) = = null ) {
this . teamManager = new TeamManager ( this ) ;
2022-04-25 14:51:34 +08:00
}
if ( this . getProfile ( ) . getUid ( ) = = 0 ) {
2022-04-20 18:48:26 -07:00
this . getProfile ( ) . syncWithCharacter ( this ) ;
2022-04-17 05:43:07 -07:00
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Check if player object exists in server
// TODO - optimize
2022-04-19 02:22:21 -07:00
GenshinPlayer exists = this . getServer ( ) . getPlayerByUid ( getUid ( ) ) ;
2022-04-17 05:43:07 -07:00
if ( exists ! = null ) {
exists . getSession ( ) . close ( ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Load from db
this . getAvatars ( ) . loadFromDatabase ( ) ;
this . getInventory ( ) . loadFromDatabase ( ) ;
this . getAvatars ( ) . postLoad ( ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
this . getFriendsList ( ) . loadFromDatabase ( ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Create world
World world = new World ( this ) ;
world . addPlayer ( this ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Add to gameserver
if ( getSession ( ) . isActive ( ) ) {
getServer ( ) . registerPlayer ( this ) ;
getProfile ( ) . setPlayer ( this ) ; // Set online
}
2022-04-25 14:51:34 +08:00
// Multiplayer setting
2022-04-17 05:43:07 -07:00
this . setProperty ( PlayerProperty . PROP_PLAYER_MP_SETTING_TYPE , this . getMpSetting ( ) . getNumber ( ) ) ;
this . setProperty ( PlayerProperty . PROP_IS_MP_MODE_AVAILABLE , 1 ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Packets
session . send ( new PacketPlayerDataNotify ( this ) ) ; // Player data
session . send ( new PacketStoreWeightLimitNotify ( ) ) ;
session . send ( new PacketPlayerStoreNotify ( this ) ) ;
session . send ( new PacketAvatarDataNotify ( this ) ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
session . send ( new PacketPlayerEnterSceneNotify ( this ) ) ; // Enter game world
2022-04-24 13:22:26 +08:00
session . send ( new PacketPlayerLevelRewardUpdateNotify ( rewardedLevels ) ) ;
2022-04-17 05:43:07 -07:00
session . send ( new PacketOpenStateUpdateNotify ( ) ) ;
// First notify packets sent
this . setHasSentAvatarDataNotify ( true ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public void onLogout ( ) {
// Leave world
if ( this . getWorld ( ) ! = null ) {
this . getWorld ( ) . removePlayer ( this ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Status stuff
this . getProfile ( ) . syncWithCharacter ( this ) ;
this . getProfile ( ) . setPlayer ( null ) ; // Set offline
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
this . getCoopRequests ( ) . clear ( ) ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
// Save to db
this . save ( ) ;
this . getTeamManager ( ) . saveAvatars ( ) ;
this . getFriendsList ( ) . save ( ) ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public enum SceneLoadState {
2022-04-25 14:51:34 +08:00
NONE ( 0 ) , LOADING ( 1 ) , INIT ( 2 ) , LOADED ( 3 ) ;
2022-04-17 05:43:07 -07:00
private final int value ;
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
private SceneLoadState ( int value ) {
this . value = value ;
}
2022-04-25 14:51:34 +08:00
2022-04-17 05:43:07 -07:00
public int getValue ( ) {
return this . value ;
}
}
}