Merge branch 'unstable' into unstable-quests

# Conflicts:
#	.gitignore
#	src/generated/main/java/emu/grasscutter/net/proto/ABJDNCBDEKIOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AKFPAANICKGOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityActionGenerateElemBallOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityAppliedAbilityOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityAppliedModifierOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityAttachedModifierOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityControlBlockOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityEmbryoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityGadgetInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityIdentifierOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityInvocationsNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityInvokeArgumentOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityInvokeEntryHeadOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityInvokeEntryOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityMetaAddAbilityOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityMetaModifierChangeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityMetaModifierDurabilityChangeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityMetaReInitOverrideMapOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityMixinRecoverInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityScalarTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityScalarValueEntryOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilityStringOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AbilitySyncStateInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AchievementAllDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AchievementOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AchievementUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ActivityInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ActivityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ActivityPushTipsDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ActivityPushTipsStateOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ActivityScheduleInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ActivityScheduleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ActivityShopSheetInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ActivityTakeWatcherRewardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ActivityTakeWatcherRewardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ActivityUpdateWatcherNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ActivityWatcherInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AddBackupAvatarTeamReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AddBackupAvatarTeamRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AddNoGachaAvatarCardNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AddNoGachaAvatarCardTransferItemOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AddQuestContentProgressReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AddQuestContentProgressRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AdjustTrackingInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AiSkillCdInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AiSyncInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AiThreatInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AkaFesDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AllWidgetDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AnchorPointDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AnimatorParameterValueInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AnimatorParameterValueInfoPairOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AnnounceDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AntiAddictNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ArenaChallengeActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ArenaChallengeMonsterLevelOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AskAddFriendNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AskAddFriendReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AskAddFriendRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AsterActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AsterLargeDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AsterLittleDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AsterLittleStageStateOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AsterMidCampInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AsterMidDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AsterProgressDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AttackHitEffectResultOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AttackResultOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarAddNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarChangeCostumeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarChangeCostumeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarChangeCostumeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarChangeElementTypeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarChangeElementTypeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarDelNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarDieAnimationEndReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarDieAnimationEndRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarEnterSceneInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarEquipAffixInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarEquipAffixStartNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarEquipChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExcelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExpeditionAllDataReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExpeditionAllDataRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExpeditionCallBackReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExpeditionCallBackRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExpeditionDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExpeditionGetRewardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExpeditionGetRewardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExpeditionInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExpeditionStartReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExpeditionStartRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarExpeditionStateOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarFetterDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarFetterInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarFetterLevelRewardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarFetterLevelRewardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarFightPropNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarFightPropUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarFlycloakChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarFollowRouteNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarGainCostumeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarGainFlycloakNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarLifeStateChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarPromoteReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarPromoteRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarPropChangeReasonNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarPropNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarRenameInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarRenameInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarSatiationDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarSatiationDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarSkillChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarSkillDepotChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarSkillInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarSkillInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarSkillMaxChargeCountNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarSkillUpgradeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarSkillUpgradeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarTeamAllDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarTeamOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarTeamResonanceInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarTeamUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarUnlockTalentNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarUpgradeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarUpgradeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarWearFlycloakReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/AvatarWearFlycloakRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BEAMFIKPMLEOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BackMyWorldRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BartenderActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BartenderLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BartenderTaskInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BatchBuyGoodsReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BatchBuyGoodsRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BattlePassAllDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BattlePassCurScheduleUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BattlePassCycleOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BattlePassMissionDelNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BattlePassMissionOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BattlePassMissionUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BattlePassProductOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BattlePassRewardTagOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BattlePassRewardTakeOptionOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BattlePassScheduleOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BattlePassUnlockStatusOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BirthdayOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BlessingActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BlitzRushActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BlitzRushStageOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BlockInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BlossomBriefInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BlossomBriefInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BlossomChestInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BonusActivityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BonusActivityInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BonusActivityInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BonusOpActivityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BossChestInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BounceConjuringActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BounceConjuringChapterInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BreakoutActionOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BreakoutBrickInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BreakoutElementReactionCounterOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BreakoutPhysicalObjectModifierOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BreakoutPhysicalObjectOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BreakoutSnapShotOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BreakoutSpawnPointOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BreakoutSyncConnectUidInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BreakoutVector2OuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BrickBreakerActivityStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BrickBreakerDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BrickBreakerLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BuoyantCombatDailyInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BuoyantCombatDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BuyBattlePassLevelReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BuyBattlePassLevelRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BuyGoodsParamOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BuyGoodsReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BuyGoodsRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BuyResinReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/BuyResinRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CFFFGFFKINKOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CKMJBOGJFMBOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CalcWeaponUpgradeReturnItemsReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CalcWeaponUpgradeReturnItemsRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CanUseSkillNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CancelFinishParentQuestNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CardProductRewardNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChallengeBriefOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChallengeDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChallengeFinishTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChangeAvatarReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChangeAvatarRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChangeEnergyReasonOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChangeGameTimeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChangeGameTimeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChangeHpReasonOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChangeMailStarNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChangeMpTeamAvatarReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChangeMpTeamAvatarRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChangeTeamNameReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChangeTeamNameRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChannelerSlabActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChannelerSlabCampOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChannelerSlabChallengeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChannelerSlabChallengeStageOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChannelerSlabOneoffDungeonOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChannellerSlabAssistInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChannellerSlabBuffInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChannellerSlabBuffSchemeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChannellerSlabLoopDungeonInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChannellerSlabLoopDungeonResultInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChannellerSlabLoopDungeonStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChapterStateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChapterStateOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CharAmusementAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CharAmusementDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CharAmusementStageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChatEmojiCollectionDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChatInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CheckAddItemExceedLimitNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CheckUgcStateReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CheckUgcStateRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CheckUgcUpdateReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CheckUgcUpdateRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChessActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChildQuestOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChooseCurAvatarTeamReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ChooseCurAvatarTeamRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CityReputationQuestInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ClientAIStateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ClientAbilityChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ClientAbilityInitFinishNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ClientCollectorDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ClientGadgetInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ClientInputTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ClientLoadingCostumeVerificationNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ClientLockGameTimeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CloseCommonTipsNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ClosedItemNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CodexDataFullNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CodexDataUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CodexTypeDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CodexTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CoinCollectDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CoinCollectLevelDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CoinCollectOperatorInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CoinCollectTeamAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CoinCollectTeamInfoDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CombatInvocationsNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CombatInvokeEntryOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CombatTypeArgumentOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CombineDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CombineFormulaDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CombineReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CombineRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CompoundBoostTakeStatusTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CompoundDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CompoundQueueDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CookDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CookRecipeDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CookRecipeDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CoopCgOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CoopChapterOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CoopPointOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CoopRewardOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CreateEntityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CreateGadgetInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CreateVehicleReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CreateVehicleRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CrucibleActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CrucibleBattleUidInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CrystalLinkActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CrystalLinkAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CrystalLinkBuffInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CrystalLinkDungeonAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CrystalLinkDungeonSettleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CrystalLinkLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CrystalLinkTeamInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CurVehicleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CustomCommonNodeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CustomDungeonFinishTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CustomDungeonResultInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CustomGadgetTreeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CutSceneBeginNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/CutSceneExtraParamOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DKFDACEPNALOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DailyDungeonEntryInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DailyTaskDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DailyTaskFilterCityReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DailyTaskFilterCityRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DailyTaskInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DailyTaskProgressNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DailyTaskUnlockedCitiesNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DataResVersionNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DealAddFriendReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DealAddFriendResultTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DealAddFriendRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DelBackupAvatarTeamReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DelBackupAvatarTeamRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DelMailReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DelMailRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DelTeamEntityNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DeleteFriendNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DeleteFriendReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DeleteFriendRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DeliveryActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DeshretObeliskGadgetInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DestroyMaterialReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DestroyMaterialRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DigActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DigMarkPointOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DoGachaReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DoGachaRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DoSetPlayerBornDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DragonSpineActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DragonSpineChapterInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DropHintNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DropItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DropItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DuelHeartDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DuelHeartLevelDifficultyInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DuelHeartLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonCandidateTeamChangeAvatarReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonCandidateTeamChangeAvatarRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonChallengeBeginNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonChallengeFinishNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonEnterPosInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonEntryInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonEntryInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonEntryInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonEntryPointInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonPlayerDieNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonPlayerDieReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonPlayerDieRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonSettleExhibitionInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonSettleNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonShowReminderNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonSlipRevivePointActivateReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonSlipRevivePointActivateRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonWayPointActivateReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonWayPointActivateRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/DungeonWayPointNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EchoShellDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EchoShellInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EffigyActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EffigyChallengeDungeonResultInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EffigyChallengeV2DetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EffigyChallengeV2LevelDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EffigyChallengeV2SettleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EffigyDailyInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ElectroherculesBattleDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ElectroherculesBattleLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ElectroherculesBattleStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EndCameraSceneLookNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EnterSceneDoneReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EnterSceneDoneRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EnterScenePeerNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EnterSceneReadyReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EnterSceneReadyRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EnterTransPointRegionNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EnterTrialAvatarActivityDungeonReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EnterTrialAvatarActivityDungeonRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EnterTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EnterWorldAreaReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EnterWorldAreaRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EntityAbilityInvokeEntryOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EntityAiSyncNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EntityAuthorityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EntityClientDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EntityClientExtraInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EntityEnvironmentInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EntityFightPropChangeReasonNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EntityFightPropUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EntityMoveInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EntityRendererChangedInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EquipOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EquipParamOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EquipRoguelikeRuneReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EquipRoguelikeRuneRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtAiSyncCombatThreatInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtAiSyncSkillCdNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtAnimatorParameterInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtAvatarLockChairReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtAvatarLockChairRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtAvatarSitDownNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtAvatarStandUpNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtBeingHitInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtCreateGadgetNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtDestroyGadgetNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtDoSkillSuccNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/EvtEntityRenderersChangedNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ExecuteGadgetLuaReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ExecuteGadgetLuaRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ExhibitionDisplayInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ExitTransPointRegionNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ExpeditionActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ExpeditionChallengeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ExpeditionPathInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ExpeditionStateOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FEEHAOJCNCGOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FeatureBlockInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FetterDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FightPropPairOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FindHilichurlAcceptQuestNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FindHilichurlDayContentInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FindHilichurlDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FindHilichurlFinishSecondQuestNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FinishedParentQuestNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FinishedParentQuestUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FishPoolInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FishtankFishInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairBalloonInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairChapterInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairDungeonSectionInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairFallInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairMinigameInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairMusicGameInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairMusicGameSettleReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairMusicGameSettleRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairMusicGameStartReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairMusicGameStartRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairMusicRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairV2DetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairV2MusicGameInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairV2PacmanInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairV2PhotoInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairV2PhotoPosDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FleurFairV2StageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FlightActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FlightDailyRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForceUpdateInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForgeDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForgeFormulaDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForgeGetQueueDataReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForgeGetQueueDataRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForgeQueueDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForgeQueueDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForgeQueueManipulateReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForgeQueueManipulateRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForgeQueueManipulateTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForgeStartReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForgeStartRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ForwardTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FoundationInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FoundationStatusOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FriendBriefOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FriendEnterHomeOptionOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FriendOnlineStateOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FungusDetailOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FungusFighterDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FungusFighterMonsterDetailOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FungusFighterV2DetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FungusFighterV2LevelDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FungusFighterV2SettleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FungusPlotStageDetailOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FungusTrainingDungeonDetailOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FungusTrainingMonsterPreviewDetailOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FungusTrainingPoolPreviewDetailOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FungusTrainingProgressDetailOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureCurModuleArrangeCountNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeBeHelpedDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeBeHelpedNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeCancelReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeCancelRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeFinishNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeHelpDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeHelpReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeHelpRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeMakeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeSlotOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeStartReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureMakeStartRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/FurnitureOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GCGFestivalDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GCGTCTavernChallengeDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GCGTCTavernChallengeDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GachaActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GachaInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GachaItemOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GachaOpenWishNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GachaStageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GachaTransferItemOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GachaUpInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GachaWishReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GachaWishRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GadgetAutoPickDropInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GadgetBornTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GadgetCrucibleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GadgetGeneralRewardInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GadgetInteractReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GadgetInteractRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GadgetPlayInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GadgetStateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GalleryStopReasonOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GameplayRecommendationElementReliquaryRequestOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GameplayRecommendationElementReliquaryResponseOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GameplayRecommendationReliquaryMainPropDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GameplayRecommendationReliquaryRequestOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GameplayRecommendationReliquaryResponseOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GatherGadgetInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GearActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GearLevelDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetActivityInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetActivityInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetActivityShopSheetInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetActivityShopSheetInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetAllH5ActivityInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetAllH5ActivityInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetAllMailNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetAllMailReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetAllMailResultNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetAllMailRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetAllUnlockNameCardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetAllUnlockNameCardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetAuthkeyReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetAuthkeyRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetBlossomBriefInfoListReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetBlossomBriefInfoListRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetChatEmojiCollectionReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetChatEmojiCollectionRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetCompoundDataReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetCompoundDataRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetDailyDungeonEntryInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetDailyDungeonEntryInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetFriendShowAvatarInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetFriendShowAvatarInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetFriendShowNameCardInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetFriendShowNameCardInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetFurnitureCurModuleArrangeCountReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetGachaInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetGachaInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetHomeExchangeWoodInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetHomeLevelUpRewardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetHomeLevelUpRewardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetInvestigationMonsterReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetInvestigationMonsterRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetMailItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetMailItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetMapAreaRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetOnlinePlayerInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetOnlinePlayerInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetOnlinePlayerListReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetOnlinePlayerListRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetOpActivityInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetOpActivityInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetParentQuestVideoKeyReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetParentQuestVideoKeyRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetPlayerAskFriendListReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetPlayerAskFriendListRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetPlayerBlacklistRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetPlayerFriendListReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetPlayerFriendListRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetPlayerHomeCompInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetPlayerSocialDetailReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetPlayerSocialDetailRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetPlayerTokenReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetPlayerTokenRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetQuestLackingResourceReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetQuestLackingResourceRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetQuestTalkHistoryReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetQuestTalkHistoryRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetRegionSearchReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetSceneAreaReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetSceneAreaRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetScenePointReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetScenePointRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetShopReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetShopRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetShopmallDataReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetShopmallDataRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetUgcBriefInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetUgcBriefInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetUgcReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetUgcRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetUgcTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetWidgetSlotReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetWidgetSlotRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetWorldMpInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GetWorldMpInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GravenInnocenceCampInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GravenInnocenceCampStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GravenInnocenceCarveInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GravenInnocenceCarveStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GravenInnocenceDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GravenInnocencePhotoInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GravenInnocencePhotoObjectInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GravenInnocencePhotoStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GravenInnocenceRaceInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GravenInnocenceRaceLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GroupSuiteNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/GroupUnloadNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/H5ActivityIdsNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/H5ActivityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HDOMFAKCLHGOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HOKJIFJPJLBOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HachiActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HachiStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HideAndSeekActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HideAndSeekMapInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HitColliderTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HitCollisionOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HitTreeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeAllUnlockedBgmIdListNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeAnimalDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeBasicInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeBasicInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeBlockArrangementInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeBlockDotPatternOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeBlockFieldDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeBlockSubFieldDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeChangeBgmNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeChangeBgmReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeChangeBgmRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeChangeEditModeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeChangeEditModeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeChangeModuleReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeChangeModuleRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeChooseModuleReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeChooseModuleRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeComfortInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeCustomFurnitureInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeCustomFurnitureInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeEditCustomFurnitureReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeEditCustomFurnitureRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeEnterEditModeFinishReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeEnterEditModeFinishRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeFurnitureCustomSuiteDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeFurnitureDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeFurnitureGroupDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeFurnitureSuiteDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeGetArrangementInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeGetArrangementInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeGetBasicInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeGetOnlineStatusReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeGetOnlineStatusRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeGroupPlayerInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopBuyGoodsReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopBuyGoodsRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopGoodsListReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopGoodsListRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopGoodsOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopInfoChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeMarkPointFurnitureDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeMarkPointNPCDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeMarkPointNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeMarkPointSceneDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeMarkPointSuiteDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeModuleComfortInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeModuleSeenReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeModuleSeenRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeModuleUnlockNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeNewUnlockedBgmIdListNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeNpcDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomePlantFieldStatusOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomePreChangeEditModeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeResourceNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeResourceOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeResourceTakeFetterExpReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeResourceTakeFetterExpRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeResourceTakeHomeCoinReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeResourceTakeHomeCoinRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeSceneArrangementInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeSceneInitFinishReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeSceneInitFinishRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeSceneJumpReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeSceneJumpRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeSeekFurnitureAllRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeSeekFurnitureGalleryScoreNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeSeekFurnitureOneRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeSeekFurniturePlayerScoreOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeUpdateArrangementInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HomeUpdateArrangementInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/HostPlayerNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InferencePageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InfernceWordInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InstableSprayAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InstableSprayDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InstableSprayDungeonSettleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InstableSprayStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InstableSprayTeamInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InterOpTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InteractTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InvestigationMonsterOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InvestigationMonsterUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InvestigationOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InvestigationQuestDailyNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InvestigationReadQuestDailyNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/InvestigationTargetOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriChessDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriChessEntranceDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriChessEntranceInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriChessEquipCardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriChessEquipCardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriChessLevelDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriChessMapDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriChessMonsterInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriFlowerDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriMasterLevelDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriMasterLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriPoetryDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IrodoriPoetryThemeDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IslandPartyDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/IslandPartyStageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ItemAddHintNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ItemCdGroupTimeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ItemGivingReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ItemGivingRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ItemHintOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ItemOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ItemParamOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ItemRenameAvatarReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ItemRenameAvatarRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/JAAACKLMLHIOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/JILBANAJEEFOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/JKFJFNMCNDNOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/JNMLLBGCBOBOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/JigsawPictureDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LCMFDAHJIBKOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LLBFJGELKIBOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LanternProjectionInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LanternProjectionLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LanternRiteActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LanternRiteFireworksChallengeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LanternRiteFireworksInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LanternRiteFireworksStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LevelupCityReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LifeStateChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LockedPersonallineDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LuminanceStoneChallengeActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LunaRiteAreaInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LunaRiteDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LunaRiteHintPointOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LunaRiteHintPointTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LunaRiteHintStatusTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/LunchBoxDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MPLevelEntityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MailChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MailCollectStateOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MailDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MailItemOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MailTextContentOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MapAreaInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MapMarkFromTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MapMarkPointOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MapMarkPointTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MarkMapReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MarkMapRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MarkNewNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MarkTargetInvestigationMonsterNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MassivePropParamOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MassivePropSyncInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MaterialDeleteInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MaterialDeleteReturnNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MaterialDeleteReturnTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MaterialDeleteUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MaterialInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MaterialOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MathQuaternionOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/McoinExchangeHcoinReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/McoinExchangeHcoinRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MichiaeMatsuriActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MichiaeMatsuriChallengePositionInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MichiaeMatsuriChestPositionInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MichiaeMatsuriStageOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MiracleRingDeliverItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MiracleRingDeliverItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MistTrialActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MistTrialBestAvatarOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MistTrialLevelDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ModifierActionOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ModifierDurabilityOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ModifierPropertyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MonsterAIConfigHashNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MonsterBornTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MonsterPointArrayRouteUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MonsterRouteOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MoonfinTrialActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MoonfinTrialLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MotionInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MotionStateOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MovingPlatformTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MpPlayRewardInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MpSettingTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MuqadasPotionActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MuqadasPotionDungeonSettleNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MuqadasPotionLevelDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MusicGameActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MusicGameRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MusicGameSettleReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MusicGameSettleRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MusicGameStartReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/MusicGameStartRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/NightCrowGadgetInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/NpcTalkReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/NpcTalkRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ObstacleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ObstacleModifyNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/OfferingInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/OfficialCustomDungeonOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/OneoffGatherPointDetectorDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/OnlinePlayerInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/OpActivityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/OpenStateChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/OpenStateUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PGHIDDKHGALOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PIHDFMDILLFOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PSPlayerApplyEnterMpReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PSPlayerApplyEnterMpRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PacmanSettleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ParamListOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ParentQuestInferenceDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ParentQuestOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ParentQuestRandomInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ParkourLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PathfindingEnterSceneReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PathfindingEnterSceneRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PersonalLineAllDataReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PersonalLineAllDataRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PersonalSceneJumpReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PersonalSceneJumpRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PhotoActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PhotoPosDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PingReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PingRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlantFlowerActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlatformChangeRouteNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlatformInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlatformStartRouteNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlatformStopRouteNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlatformTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayTeamEntityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerApplyEnterMpNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerApplyEnterMpReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerApplyEnterMpResultNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerApplyEnterMpResultReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerApplyEnterMpResultRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerApplyEnterMpRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerChatNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerChatReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerChatRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerCompoundMaterialBoostReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerCompoundMaterialBoostRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerCompoundMaterialReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerCompoundMaterialRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerCookArgsReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerCookArgsRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerCookReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerCookRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerDieTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerEnterDungeonReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerEnterDungeonRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerEnterSceneInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerEnterSceneNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerForceExitRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerGameTimeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerGetForceQuitBanInfoReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerGetForceQuitBanInfoRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerHomeCompInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerHomeCompInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerInvestigationAllInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerInvestigationNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerInvestigationTargetNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerLevelRewardUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerLocationInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerLoginReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerLoginRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerPropChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerPropChangeReasonNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerPropNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerQuitDungeonReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerRTTInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerSetPauseReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerSetPauseRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerStoreNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerTimeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerWidgetInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerWorldLocationInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerWorldSceneInfoListNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PlayerWorldSceneInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PostEnterSceneReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PostEnterSceneRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PotionActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PotionAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PotionDungeonResultInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PotionLevelDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PotionStageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PrivateChatNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PrivateChatReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ProfilePictureChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ProfilePictureOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PropChangeReasonOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PropPairOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PropValueOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ProtEntityTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ProudSkillChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ProudSkillExtraLevelNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PullPrivateChatReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PullPrivateChatRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PullRecentChatReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/PullRecentChatRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QueryCodexMonsterBeKilledNumReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QueryCodexMonsterBeKilledNumRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QueryCurrRegionHttpRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QueryFilterOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QueryPathReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QueryPathRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QueryRegionListHttpRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestCreateEntityReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestCreateEntityRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestDelNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestDestroyEntityReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestDestroyEntityRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestDestroyNpcReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestDestroyNpcRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestGlobalVarNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestGlobalVarOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestListNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestListUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestProgressUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestRenameAvatarReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestRenameAvatarRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestTransmitReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestTransmitRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestUpdateQuestTimeVarNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestUpdateQuestVarNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestUpdateQuestVarReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestUpdateQuestVarRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuestVarOpOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/QuickUseWidgetRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReadMailNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReadPrivateChatReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReceivedTrialAvatarActivityRewardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReceivedTrialAvatarActivityRewardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RecordUsageOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RegionInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RegionSimpleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReliquaryDecomposeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReliquaryDecomposeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReliquaryFilterStateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReliquaryFilterStateSaveNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReliquaryOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReliquaryPromoteReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReliquaryPromoteRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReliquaryUpgradeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ReliquaryUpgradeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ResVersionConfigOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ResinChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ResinCostTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RobotPushPlayerDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RockBoardExploreDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RockBoardExploreStageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RogueAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RogueDiaryActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RogueDiaryAvatarDisableStatusOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RogueDiaryDungeonRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RogueDiaryDungeonSettleNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RogueDiaryProgressOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RogueDiaryStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RogueShowAvatarTeamInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RogueStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RoguelikeDungeonActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RoguelikeDungeonSettleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RoguelikeGadgetInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RoguelikeRuneRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RoguelikeSettleCoinInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RoguelikeShikigamiRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RouteOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RoutePointChangeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/RoutePointOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SalesmanActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SalesmanDeliverItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SalesmanDeliverItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SalesmanStatusTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SalvageBundleChallengeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SalvageChallengeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SalvageScoreChallengeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SalvageStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SandwormCannonDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SaveUgcReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SaveUgcRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneAreaUnlockNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneAreaWeatherNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneAudioNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneAvatarStaminaStepReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneEntityAiInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneEntityAppearNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneEntityDisappearNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneEntityDrownReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneEntityDrownRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneEntityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneEntityMoveNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneFishInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneForceLockNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneForceUnlockNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneGadgetInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneGalleryHomeSeekFurnitureInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneInitFinishRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneKickPlayerReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneKickPlayerRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneMonsterInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneNpcInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ScenePlayerInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ScenePlayerInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ScenePlayerLocationNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ScenePlayerSoundNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ScenePointUnlockNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneReliquaryInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneRouteChangeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneRouteChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneTeamAvatarOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneTeamUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneTimeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneTransToPointReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneTransToPointRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SceneWeaponInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ScreenInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampActivityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampContributeItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampContributeItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampSectionInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampV3CampInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampV3CampStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampV3DetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampV3RaceInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampV3RaceLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampV3ShadowInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampV3ShadowLevelInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeaLampV3ShadowStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SeeMonsterReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SelectWorktopOptionReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SelectWorktopOptionRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ServantInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ServerAnnounceNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ServerAnnounceRevokeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ServerBuffChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ServerBuffOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ServerCondMeetQuestListUpdateNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ServerGlobalValueChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ServerTimeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetBattlePassViewedReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetBattlePassViewedRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetChatEmojiCollectionReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetChatEmojiCollectionRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetEntityClientDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetEquipLockStateReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetEquipLockStateRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetFriendEnterHomeOptionReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetFriendEnterHomeOptionRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetIsAutoUnlockSpecificEquipReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetIsAutoUnlockSpecificEquipRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetNameCardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetNameCardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetOpenStateReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetOpenStateRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerBirthdayReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerBirthdayRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerBornDataReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerBornDataRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerHeadImageReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerHeadImageRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerNameReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerNameRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerPropReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerPropRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerSignatureReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetPlayerSignatureRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetUpAvatarTeamReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetUpAvatarTeamRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetUpLunchBoxWidgetReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetUpLunchBoxWidgetRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetWidgetSlotReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SetWidgetSlotRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ShopCardProductOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ShopConcertProductOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ShopGoodsOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ShopMcoinProductOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ShopOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ShortAbilityHashPairOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ShowAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ShowClientGuideNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ShowCommonTipsNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ShowEquipOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SkipPlayerGameTimeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SkipPlayerGameTimeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SkyCrystalDetectorDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SkyCrystalDetectorQuickUseResultOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SocialDetailOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SocialShowAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SorushTrialDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SpiceActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SpiceStageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/StatueGadgetInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/StopServerInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/StoreItemChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/StoreItemDelNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/StoreTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/StoreWeightLimitNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/StrengthenPointDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SummerTimeDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SummerTimeDungeonInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SummerTimeSprintBoatInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SummerTimeSprintBoatRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SummerTimeStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SummerTimeV2BoatStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SummerTimeV2DetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SummerTimeV2DungeonSettleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SummerTimeV2DungeonStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SumoActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SumoAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SumoDungeonSettleNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SumoStageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SumoTeamDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SyncScenePlayTeamEntityNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/SyncTeamEntityNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeAchievementGoalRewardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeAchievementGoalRewardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeAchievementRewardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeAchievementRewardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeBackGivingItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeBackGivingItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeBattlePassMissionPointReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeBattlePassMissionPointRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeBattlePassRewardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeBattlePassRewardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeCityReputationParentQuestReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeCityReputationParentQuestRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeCompoundOutputReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeCompoundOutputRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeFurnitureMakeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeFurnitureMakeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeInvestigationRewardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeInvestigationRewardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeInvestigationTargetRewardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeInvestigationTargetRewardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeMaterialDeleteReturnReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeMaterialDeleteReturnRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakePlayerLevelRewardReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakePlayerLevelRewardRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeoffEquipReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TakeoffEquipRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TanukiTravelActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TanukiTravelFinishGuideQuestNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TanukiTravelLevelDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TeamChainChooseAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TeamChainDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TeamChainSettleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TeamChainStageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TeamEnterSceneInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TeamEntityInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ToTheMoonEnterSceneReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ToTheMoonQueryPathReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/ToTheMoonQueryPathRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerAllDataReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerAllDataRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerBriefDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerCurLevelRecordChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerCurLevelRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerEnterLevelReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerEnterLevelRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerFloorRecordChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerFloorRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerLevelEndNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerLevelRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerLevelStarCondDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerLevelStarCondNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerMiddleLevelChangeTeamNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerMonthlyBriefOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerTeamOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerTeamSelectReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TowerTeamSelectRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TrackingIOInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TreasureMapActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TreasureMapBonusChallengeInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TreasureMapRegionInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TreasureMapRegionInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TreasureSeelieActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TreasureSeelieRegionDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TrialAvatarActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TrialAvatarActivityRewardDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TrialAvatarFirstPassDungeonNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TrialAvatarGrantRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TrialAvatarInDungeonIndexNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TrialAvatarInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TriggerCreateGadgetToEquipPartNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TryEnterHomeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/TryEnterHomeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UgcActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UgcMusicBriefInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UgcMusicNoteOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UgcMusicRecordOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UgcMusicTrackOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UgcNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UgcTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/Uint32PairOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UnionCmdNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UnionCmdOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UnlockAvatarTalentReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UnlockAvatarTalentRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UnlockNameCardNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UnlockPersonalLineReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UnlockPersonalLineRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UnlockTransPointReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UnlockTransPointRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UnlockedFurnitureFormulaDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UnlockedFurnitureSuiteDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UpdateAbilityCreatedMovingPlatformNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UpdatePlayerShowAvatarListReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UpdatePlayerShowAvatarListRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UpdatePlayerShowNameCardListReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UpdatePlayerShowNameCardListRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UseItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/UseItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/Vector3IntOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VectorOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VectorPlaneOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VehicleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VehicleInteractReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VehicleInteractRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VehicleInteractTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VehicleLocationInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VehicleMemberOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VehicleStaminaNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintageActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintageBoothUsedItemDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintageCampChallengeLevelDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintageCampChallengeStageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintageHuntingStageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintageMarketDealInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintageMarketDeliverItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintageMarketDeliverItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintageMarketInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintageMarketStoreInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintageMarketTraderInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintagePresentLevelDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VintagePresentStageDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/VisionTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WaterSpiritActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WeaponAwakenReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WeaponAwakenRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WeaponOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WeaponPromoteReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WeaponPromoteRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WeaponUpgradeReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WeaponUpgradeRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WearEquipReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WearEquipRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WeatherInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WeatherWizardDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WeekendDjinnInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WeeklyBossResinDiscountInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetCoolDownDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetCoolDownNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetCreateLocationInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetCreatorInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetCreatorOpTypeOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetDoBagReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetDoBagRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetGadgetAllDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetGadgetDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetGadgetDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetSlotChangeNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetSlotDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetSlotOpOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WidgetSlotTagOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WindFieldDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WindFieldDungeonFailReasonOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WindFieldDungeonSettleInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WindFieldStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WindSeedClientNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WindSeedType1NotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampAcceptAllGiveItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampAcceptAllGiveItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampAcceptGiveItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampAcceptGiveItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampAcceptItemResultInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampActivityDetailInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampGetCanGiveFriendItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampGetCanGiveFriendItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampGetRecvItemListReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampGetRecvItemListRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampGiveFriendItemReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampGiveFriendItemRspOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampRaceStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampRecvItemDataOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampRecvItemNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WinterCampStageInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorktopInfoOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorktopOptionNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorldChestOpenNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorldDataNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorldOwnerBlossomBriefInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorldOwnerDailyTaskNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorldPlayerDieNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorldPlayerInfoNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorldPlayerLocationNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorldPlayerRTTNotifyOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorldPlayerReviveReqOuterClass.java
#	src/generated/main/java/emu/grasscutter/net/proto/WorldPlayerReviveRspOuterClass.java
#	src/main/java/emu/grasscutter/GameConstants.java
#	src/main/java/emu/grasscutter/Grasscutter.java
#	src/main/java/emu/grasscutter/command/commands/SetPropCommand.java
#	src/main/java/emu/grasscutter/config/ConfigContainer.java
#	src/main/java/emu/grasscutter/config/Configuration.java
#	src/main/java/emu/grasscutter/data/excels/ItemData.java
#	src/main/java/emu/grasscutter/data/excels/SceneData.java
#	src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java
#	src/main/java/emu/grasscutter/game/managers/ResinManager.java
#	src/main/java/emu/grasscutter/game/player/Player.java
#	src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java
#	src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java
#	src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java
#	src/main/java/emu/grasscutter/tools/Dumpers.java
#	src/main/java/emu/grasscutter/utils/Crypto.java
#	src/main/java/emu/grasscutter/utils/FileUtils.java
#	src/main/java/emu/grasscutter/utils/Language.java
#	src/main/java/emu/grasscutter/utils/StartupArguments.java
#	src/main/java/emu/grasscutter/utils/Utils.java
This commit is contained in:
KingRainbow44 2023-05-08 01:31:06 -04:00
commit 3e183ff9d1
No known key found for this signature in database
GPG Key ID: FC2CB64B00D257BE
67 changed files with 9766 additions and 31 deletions

View File

@ -10,5 +10,5 @@ max_line_length = 120
tab_width = 4
trim_trailing_whitespace = true
[{*.json,*.xml}]
[{*.json,*.xml,*.yml}]
indent_size = 2

82
.github/workflows/handbook.yml vendored Normal file
View File

@ -0,0 +1,82 @@
name: "Handbook"
on:
workflow_dispatch: ~
push:
paths:
- "src/handbook/**.tsx"
branches:
- "development"
- "unstable"
pull_request:
paths:
- "src/handbook/**.tsx"
types:
- opened
- synchronize
- reopened
jobs:
Lint-Code:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: '17'
- name: Cache node modules
uses: actions/cache@v2
with:
path: |
~/.npm
~/.cache
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
working-directory: src/handbook
run: npm install --force
- name: Run linter
working-directory: src/handbook
run: npm run lint
- run: git config --global user.name "github-actions"
- run: git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Commit changes
if: ${{ github.event_name == 'push' }}
run: git add -u && git commit -m "Lint Code [skip actions]" || true
- name: Push changes
if: ${{ github.event_name == 'push' }}
run: git push --set-upstream --force origin ${{ github.ref }}
Build-Handbook:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: '17'
- name: Cache node modules
uses: actions/cache@v2
with:
path: |
~/.npm
~/.cache
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
working-directory: src/handbook
run: npm install --force
- name: Build handbook
working-directory: src/handbook
run: npm run build
- name: Upload build
uses: actions/upload-artifact@v3
with:
name: Handbook
path: src/handbook/dist/*.html

4
.gitignore vendored
View File

@ -73,6 +73,9 @@ mongod.exe
gacha-mapping.js
mappings.js
BuildConfig.java
data/hk4e/announcement/
src/main/resources/handbook.html
# lombok
/.apt_generated/
@ -80,7 +83,6 @@ BuildConfig.java
# macOS
.DS_Store
.directory
data/hk4e/announcement/
# Hotswap Agent
hotswap-agent.properties

27
src/handbook/.gitignore vendored Normal file
View File

@ -0,0 +1,27 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Handbook data
data/

12
src/handbook/.prettierrc Normal file
View File

@ -0,0 +1,12 @@
{
"arrowParens": "always",
"bracketSpacing": true,
"endOfLine": "lf",
"jsxSingleQuote": false,
"jsxBracketSameLine": false,
"semi": true,
"singleQuote": false,
"tabWidth": 4,
"trailingComma": "none",
"useTabs": false
}

View File

@ -0,0 +1,25 @@
import tailwind from "tailwindcss";
import autoprefixer from "autoprefixer";
import cssnanoPlugin from "cssnano";
import tailwindConfig from "./tailwind.config.js";
const mode = process.env.NODE_ENV;
const dev = mode === "development";
export default {
plugins: (() => {
let plugins = [
// Some plugins, like TailwindCSS/Nesting, need to run before Tailwind.
tailwind(tailwindConfig),
// But others, like autoprefixer, need to run after.
autoprefixer()
];
!dev && cssnanoPlugin({
preset: "default"
});
return plugins;
})()
}

View File

@ -0,0 +1,9 @@
export default {
content: ["./src/**/*.{html,js,tsx,ts}"],
mode: "jit",
theme: {
extend: {}
},
darkMode: "class",
plugins: []
};

View File

@ -0,0 +1,32 @@
# Handbook Data
Use Grasscutter's dumpers to generate the data to put here.
## Files Required
- `commands.json`
- `entities.csv`
- `avatars.csv`
- `scenes.csv`
- `items.csv`
# Item Icon Notes
- Artifacts: `https://bbs.hoyolab.com/hoyowiki/picture/reliquary/(name)/(piece)_icon.png`
- Alternate source: `https://api.ambr.top/assets/UI/reliquary/UI_RelicIcon_(set)_(piece).png`
- `xxxx4` - `flower_of_life`
- `xxxx5` - `sands_of_eon`
- `xxxx3` - `circlet_of_logos`/`plume_of_death`
- Use `circlet_of_logos` with a complete set
- Use `plume_of_death` with part of a set.
- `xxxx2` - `plume_of_death`
- `xxxx1` - `goblet_of_eonothem`
- Miscellaneous Items: `https://bbs.hoyolab.com/hoyowiki/picture/object/(name)_icon.png`
- Includes: materials, quest items, food, etc.
- Alternate source: `https://api.ambr.top/assets/UI/UI_ItemIcon_(id).png`
- Avatars/Avatar Items: `https://bbs.hoyolab.com/hoyowiki/picture/character/(name)_icon.png`
- Avatar Items are between ranges `1001` and `1099`.
- Weapons: `https://api.ambr.top/assets/UI/UI_EquipIcon_(type)_(name).png`
- Furniture: `https://api.ambr.top/assets/UI/furniture/UI_Homeworld_(location)_(name).png`
- Monsters: `https://api.ambr.top/assets/UI/monster/UI_MonsterIcon_(type)_(variant).png`
# Credits
- [`...List.json` files](https://raw.githubusercontent.com/Dituon/grasscutter-command-helper/main/data/en-US) - Grasscutter Command Helper
- [Internal Asset API](https://ambr.top) - Project Amber

12
src/handbook/index.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GM Handbook</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

5847
src/handbook/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

50
src/handbook/package.json Normal file
View File

@ -0,0 +1,50 @@
{
"name": "handbook",
"description": "The ultimate anime game handbook!",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"postinstall": "npx patch-package",
"lint": "npx prettier --write \"src/**/*.{ts,tsx,js,jsx,json,md}\""
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-virtualized": "^9.22.3",
"events": "^3.3.0"
},
"devDependencies": {
"typescript": "^4.9.3",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/react-virtualized": "^9.21.21",
"@types/events": "^3.0.0",
"vite": "^4.2.0",
"vite-plugin-svgr": "^2.4.0",
"vite-tsconfig-paths": "^4.0.7",
"vite-plugin-singlefile": "^0.13.5",
"@vitejs/plugin-react-swc": "^3.0.0",
"@rollup/plugin-dsv": "^3.0.2",
"sass": "^1.58.3",
"cssnano": "^5.1.15",
"tailwindcss": "^3.2.7",
"autoprefixer": "^10.4.13",
"postcss": "^8.4.21",
"postcss-load-config": "^4.0.1",
"postcss-font-magician": "^3.0.0",
"prettier": "^2.8.7",
"patch-package": "^6.5.1"
}
}

View File

@ -0,0 +1,10 @@
diff --git a/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js b/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js
index d00f0f1..42456dc 100644
--- a/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js
+++ b/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js
@@ -71,4 +71,3 @@ export function unregisterScrollListener(component, element) {
}
}
}
-import { bpfrpt_proptype_WindowScroller } from "../WindowScroller.js";
\ No newline at end of file

View File

@ -0,0 +1,146 @@
import commands from "@data/commands.json";
import entities from "@data/entities.csv";
import avatars from "@data/avatars.csv";
import scenes from "@data/scenes.csv";
import items from "@data/items.csv";
import { Quality, ItemType, ItemCategory, SceneType } from "@backend/types";
import type { Command, Avatar, Item, Scene, Entity } from "@backend/types";
import { inRange } from "@app/utils";
type AvatarDump = { [key: number]: Avatar };
type CommandDump = { [key: string]: Command };
type TaggedItems = { [key: number]: Item[] };
/**
* @see {@file src/handbook/data/README.md}
*/
export const sortedItems: TaggedItems = {
[ItemCategory.Constellation]: [], // Range: 1102 - 11xx
[ItemCategory.Avatar]: [], // Range: 1002 - 10xx
[ItemCategory.Weapon]: [],
[ItemCategory.Artifact]: [],
[ItemCategory.Furniture]: [],
[ItemCategory.Material]: [],
[ItemCategory.Miscellaneous]: []
};
/**
* Setup function for this file.
* Sorts all items into their respective categories.
*/
export function setup(): void {
getItems().forEach((item) => {
switch (item.type) {
case ItemType.Weapon:
sortedItems[ItemCategory.Weapon].push(item);
break;
case ItemType.Material:
sortedItems[ItemCategory.Material].push(item);
break;
case ItemType.Furniture:
sortedItems[ItemCategory.Furniture].push(item);
break;
case ItemType.Reliquary:
sortedItems[ItemCategory.Artifact].push(item);
break;
}
// Sort constellations.
if (inRange(item.id, 1102, 1199)) {
sortedItems[ItemCategory.Constellation].push(item);
}
// Sort avatars.
if (inRange(item.id, 1002, 1099)) {
sortedItems[ItemCategory.Avatar].push(item);
}
});
}
/**
* Fetches and casts all commands in the file.
*/
export function getCommands(): CommandDump {
return commands as CommandDump;
}
/**
* Fetches and lists all the commands in the file.
*/
export function listCommands(): Command[] {
return Object.values(getCommands());
}
/**
* Fetches and casts all entities in the file.
*/
export function getEntities(): Entity[] {
return entities.map((entry) => {
const values = Object.values(entry) as string[];
const id = parseInt(values[0]);
return {
id,
name: values[1],
internal: values[2]
};
});
}
/**
* Fetches and casts all avatars in the file.
*/
export function getAvatars(): AvatarDump {
const map: AvatarDump = {};
avatars.forEach((avatar) => {
const values = Object.values(avatar) as [string, string, string];
const id = parseInt(values[0]);
map[id] = {
id,
name: values[1],
quality: values[2] as Quality
};
});
return map;
}
/**
* Fetches and lists all the avatars in the file.
*/
export function listAvatars(): Avatar[] {
return Object.values(getAvatars());
}
/**
* Fetches and casts all scenes in the file.
*/
export function getScenes(): Scene[] {
return scenes.map((entry) => {
const values = Object.values(entry) as string[];
const id = parseInt(values[0]);
return {
id,
identifier: values[1],
type: values[2] as SceneType
};
});
}
/**
* Fetches and casts all items in the file.
*/
export function getItems(): Item[] {
return items.map((entry) => {
const values = Object.values(entry) as string[];
const id = parseInt(values[0]);
return {
id,
name: values[1],
type: values[3] as ItemType,
quality: values[2] as Quality,
icon: values[4]
};
});
}

View File

@ -0,0 +1,100 @@
import { EventEmitter } from "events";
import type { Page } from "@backend/types";
import { isPage } from "@backend/types";
const emitter = new EventEmitter();
const navigation = new EventEmitter();
let navStack: Page[] = [];
let currentPage: number | null = -1;
/**
* Sets up the event system.
*/
export function setup(): void {
window.onpopstate = (event) => {
navigate(event.state, false);
};
setTimeout(() => {
// Check if the window's href is a page.
const page = window.location.href.split("/").pop();
if (page == undefined || page == "") return;
// Convert the page to a Page type.
const pageName = page.charAt(0).toUpperCase() + page.slice(1);
const pageType = pageName as Page;
// Navigate to the page.
isPage(page) && navigate(pageType, false);
}, 3e2);
}
/**
* Adds a navigation listener.
*
* @param listener The listener to add.
*/
export function addNavListener(listener: (page: Page) => void) {
navigation.on("navigate", listener);
}
/**
* Removes a navigation listener.
*
* @param listener The listener to remove.
*/
export function removeNavListener(listener: (page: Page) => void) {
navigation.off("navigate", listener);
}
/**
* Navigates to a page.
* Returns the last page.
*
* @param page The page to navigate to.
* @param update Whether to update the state or not.
*/
export function navigate(page: Page, update: boolean = true): Page | null {
// Navigate to the new page.
const lastPage = currentPage;
navigation.emit("navigate", page);
if (update) {
// Set the current page.
navStack.push(page);
currentPage = navStack.length - 1;
// Add the page to the window history.
window.history.pushState(page, page, "/" + page.toLowerCase());
}
return lastPage ? navStack[lastPage] : null;
}
/**
* Goes back or forward in the navigation stack.
*
* @param forward Whether to go forward or not.
*/
export function go(forward: boolean): void {
if (currentPage == undefined) return;
// Get the new page.
const newPage = forward ? currentPage + 1 : currentPage - 1;
if (newPage < 0 || newPage >= navStack.length) return;
// Navigate to the new page.
currentPage = newPage;
navigation.emit("navigate", navStack[newPage]);
// Update the window history.
window.history.pushState(navStack[newPage], navStack[newPage], "/" + navStack[newPage].toLowerCase());
}
// This is the global event system.
export default emitter;
// @ts-ignore
window["emitter"] = emitter;
// @ts-ignore
window["navigate"] = navigate;

8
src/handbook/src/backend/files.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
declare module "*.svg" {
export const ReactComponent: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
}
declare module "*.csv" {
const content: any[];
export default content;
}

View File

@ -0,0 +1,74 @@
import type { CommandResponse } from "@backend/types";
let targetPlayer = 0; // The UID of the target player.
/**
* Sets the target player.
*
* @param player The UID of the target player.
*/
export function setTargetPlayer(player: number): void {
targetPlayer = player;
console.log(`Target Player is now: ${targetPlayer}`);
}
/**
* Validates a number.
*
* @param value The number to validate.
*/
function invalid(value: number): boolean {
return isNaN(value) || value < 0;
}
/**
* Grants an avatar to a player.
*
* @param avatar The avatar's ID.
* @param level The avatar's level.
* @param constellations The avatar's unlocked constellations.
* @param talents The level for the avatar's talents.
*/
export async function grantAvatar(
avatar: number,
level = 90,
constellations = 6,
talents = 6
): Promise<CommandResponse> {
// Validate the numbers.
if (invalid(avatar) || invalid(level) || invalid(constellations) || invalid(talents))
return { status: -1, message: "Invalid arguments." };
return await fetch(`https://localhost:443/handbook/avatar`, {
method: "POST",
body: JSON.stringify({
player: targetPlayer.toString(),
avatar: avatar.toString(),
level,
constellations,
talentLevels: talents
})
}).then((res) => res.json());
}
/**
* Gives an item to the player.
* This does not support weapons.
* This does not support relics.
*
* @param item The item's ID.
* @param amount The amount of the item to give.
*/
export async function giveItem(item: number, amount = 1): Promise<CommandResponse> {
// Validate the number.
if (isNaN(amount) || amount < 1) return { status: -1, message: "Invalid amount." };
return await fetch(`https://localhost:443/handbook/item`, {
method: "POST",
body: JSON.stringify({
player: targetPlayer.toString(),
item: item.toString(),
amount
})
}).then((res) => res.json());
}

View File

@ -0,0 +1,159 @@
export type Page = "Home" | "Commands" | "Avatars" | "Items" | "Entities" | "Scenes";
export type Days = "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday";
export type Command = {
name: string[];
description: string;
usage: string[];
permission: string[];
target: Target;
};
export type Avatar = {
name: string;
quality: Quality;
id: number;
};
export type Scene = {
identifier: string;
type: SceneType;
id: number;
};
export type Item = {
id: number;
name: string;
quality: Quality;
type: ItemType;
icon: string;
};
export type Entity = {
id: number;
name: string;
internal: string;
};
// Exported from Project Amber.
export type ItemInfo = {
response: number | 200 | 404;
data: {
name: string;
description: string;
type: string;
recipe: boolean;
mapMark: boolean;
source: {
name: string;
type: string | "domain";
days: Days;
}[];
icon: string;
rank: 1 | 2 | 3 | 4 | 5;
route: string;
};
};
// Exported from Project Amber.
export type EntityInfo = {
response: number | 200 | 404;
data: {
id: number;
name: string;
type: string;
icon: string;
route: string;
title: string;
specialName: string;
description: string;
entries: any[];
tips: null;
};
};
export enum Target {
None = "NONE",
Offline = "OFFLINE",
Player = "PLAYER",
Online = "ONLINE"
}
export enum Quality {
Legendary = "LEGENDARY",
Epic = "EPIC",
Rare = "RARE",
Uncommon = "UNCOMMON",
Common = "COMMON",
Unknown = "UNKNOWN"
}
export enum ItemType {
None = "ITEM_NONE",
Virtual = "ITEM_VIRTUAL",
Material = "ITEM_MATERIAL",
Reliquary = "ITEM_RELIQUARY",
Weapon = "ITEM_WEAPON",
Display = "ITEM_DISPLAY",
Furniture = "ITEM_FURNITURE"
}
export enum SceneType {
None = "SCENE_NONE",
World = "SCENE_WORLD",
Dungeon = "SCENE_DUNGEON",
Room = "SCENE_ROOM",
HomeWorld = "SCENE_HOME_WORLD",
HomeRoom = "SCENE_HOME_ROOM",
Activity = "SCENE_ACTIVITY"
}
export enum ItemCategory {
Constellation,
Avatar,
Weapon,
Artifact,
Furniture,
Material,
Miscellaneous
}
export type CommandResponse = {
status: number | 200 | 500;
message: string;
};
/**
* Checks if a string is a page.
*
* @param page The string to check.
*/
export function isPage(page: string): page is Page {
return ["Home", "Commands", "Avatars", "Items", "Entities", "Scenes"].includes(page);
}
/**
* Converts an item type to a string.
*
* @param type The item type to convert.
*/
export function itemTypeToString(type: ItemType): string {
switch (type) {
default:
return "Unknown";
case ItemType.None:
return "None";
case ItemType.Virtual:
return "Virtual";
case ItemType.Material:
return "Material";
case ItemType.Reliquary:
return "Reliquary";
case ItemType.Weapon:
return "Weapon";
case ItemType.Display:
return "Display";
case ItemType.Furniture:
return "Furniture";
}
}

View File

@ -0,0 +1,54 @@
html {
--background-color: #346b77;
--secondary-color: #418493;
--accent-color: #5abcb9;
--text-primary-color: #FFFFFF;
--legendary-color: #926d45;
--epic-color: #7b5c90;
overflow: hidden;
}
body {
margin: 0;
padding: 0;
height: 100vh;
width: 100%;
overflow: hidden;
#root {
height: 100%;
width: 100%;
}
* {
font-family: 'SDK_SC_Web', 'SDK_JP_Web', 'Poppins', sans-serif;
}
svg:focus {
outline: none;
}
}
.App {
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
}
::-webkit-scrollbar {
width: 5px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--accent-color);
border-radius: 10px;
}

View File

@ -0,0 +1,28 @@
p {
color: var(--text-primary-color);
margin: 0;
}
h1 {
color: var(--text-primary-color);
font-style: normal;
font-weight: normal;
font-size: 48px;
margin: 0;
}
h2 {
color: var(--text-primary-color);
font-style: normal;
font-weight: 600;
font-size: 24px;
margin: 0;
}
h3 {
color: var(--text-primary-color);
font-style: normal;
font-weight: 600;
font-size: 18px;
margin: 0;
}

View File

@ -0,0 +1,4 @@
.GridRow {
display: flex;
flex-direction: row;
}

View File

@ -0,0 +1,33 @@
.AvatarsPage {
display: flex;
height: 100%;
width: 100%;
background-color: var(--background-color);
flex-direction: column;
padding: 24px;
}
.AvatarsPage_Title {
max-width: 275px;
max-height: 60px;
font-size: 48px;
font-weight: bold;
text-align: center;
margin-bottom: 30px;
}
.AvatarsPage_List {
display: grid;
gap: 15px 15px;
max-width: 90%;
grid-template-columns: repeat(12, 100px);
margin-bottom: 28px;
overflow-y: scroll;
}

View File

@ -0,0 +1,30 @@
.CommandsPage {
display: flex;
height: 100%;
width: 100%;
background-color: var(--background-color);
flex-direction: column;
padding: 24px;
}
.CommandsPage_Title {
max-width: 275px;
max-height: 60px;
font-size: 48px;
font-weight: bold;
text-align: center;
margin-bottom: 30px;
}
.CommandsPage_List {
display: flex;
flex-direction: column;
gap: 15px;
margin-bottom: 28px;
overflow-y: scroll;
}

View File

@ -0,0 +1,93 @@
.EntitiesPage {
display: flex;
height: 100%;
width: 100%;
flex-direction: row;
justify-content: space-between;
background-color: var(--background-color);
padding: 24px;
}
.EntitiesPage_Content {
display: flex;
flex-direction: column;
width: 80%;
}
.EntitiesPage_Header {
display: flex;
flex-direction: row;
gap: 30px;
align-content: center;
margin-bottom: 30px;
}
.EntitiesPage_Title {
max-width: 230px;
max-height: 60px;
font-size: 48px;
font-weight: bold;
text-align: center;
justify-content: center;
}
.EntitiesPage_Search {
display: flex;
width: 100%;
height: 100%;
max-width: 465px;
max-height: 60px;
box-sizing: border-box;
align-items: center;
border-radius: 10px;
background-color: var(--secondary-color);
}
.EntitiesPage_Input {
background-color: transparent;
border: none;
color: var(--text-primary-color);
font-size: 20px;
width: 100%;
padding: 11px;
&:focus, &:active {
outline: none;
}
}
.EntitiesPage_Input::placeholder {
color: var(--text-secondary-color);
opacity: 1;
}
.EntitiesPage_List {
display: grid;
gap: 15px 15px;
grid-template-columns: repeat(15, 100px);
margin-bottom: 28px;
overflow-y: scroll;
}
.EntitiesPage_Card {
display: flex;
width: 100%;
max-width: 300px;
min-height: 300px;
max-height: 700px;
align-self: center;
}

View File

@ -0,0 +1,151 @@
.HomePage {
display: flex;
height: 100%;
width: 100%;
background-color: var(--background-color);
flex-direction: column;
justify-content: space-between;
div {
display: flex;
}
}
.HomePage_Top {
display: flex;
width: 100%;
height: 80%;
flex-direction: column;
align-items: center;
gap: 24px;
}
.HomePage_Title {
margin-top: 31px;
margin-bottom: 15px;
}
.HomePage_Buttons {
width: 100%;
height: 40%;
max-width: 1376px;
max-height: 256px;
gap: 24px;
justify-content: center;
flex-wrap: wrap;
}
.HomePage_Bottom {
display: flex;
height: 50%;
max-height: 125px;
flex-direction: row;
justify-content: space-between;
}
.HomePage_Box {
display: flex;
background-color: var(--secondary-color);
}
.HomePage_Disclaimer {
display: flex;
flex-direction: row;
justify-content: space-between;
background-color: var(--secondary-color);
width: 50%;
height: 100%;
max-width: 630px;
max-height: 93px;
margin: 0 0 0 60px;
border-radius: 10px;
box-sizing: border-box;
padding: 11px;
:nth-child(1) {
font-size: 24px;
max-height: 30px;
display: flex;
flex-direction: column;
}
p {
font-size: 18px;
max-height: 40px;
}
}
.HomePage_Discord {
max-height: 40px;
max-width: 150px;
gap: 8px;
align-self: center;
align-items: center;
svg {
width: 100%;
height: 100%;
max-width: 44px;
max-height: 30px;
}
p {
font-size: 16px;
}
}
.HomePage_Text {
display: flex;
flex-direction: column;
background-color: var(--secondary-color);
max-width: 300px;
max-height: 80px;
margin: 13px 60px 0 0;
border-radius: 10px;
box-sizing: border-box;
padding: 11px;
}
.HomePage_Credits {
display: flex;
flex-direction: row;
gap: 5px;
max-height: 18px;
padding-bottom: 5px;
:nth-child(1) {
font-size: 18px;
font-weight: bold;
}
:nth-child(2) {
font-size: 10px;
align-self: center;
}
}
.HomePage_Links {
display: flex;
flex-wrap: wrap;
a {
color: var(--text-primary-color);
text-decoration: none;
padding-right: 10px;
}
}

View File

@ -0,0 +1,93 @@
.ItemsPage {
display: flex;
height: 100%;
width: 100%;
flex-direction: row;
justify-content: space-between;
background-color: var(--background-color);
padding: 24px;
}
.ItemsPage_Content {
display: flex;
flex-direction: column;
width: 80%;
}
.ItemsPage_Header {
display: flex;
flex-direction: row;
gap: 30px;
align-content: center;
margin-bottom: 30px;
}
.ItemsPage_Title {
max-width: 130px;
max-height: 60px;
font-size: 48px;
font-weight: bold;
text-align: center;
justify-content: center;
}
.ItemsPage_Search {
display: flex;
width: 100%;
height: 100%;
max-width: 465px;
max-height: 60px;
box-sizing: border-box;
align-items: center;
border-radius: 10px;
background-color: var(--secondary-color);
}
.ItemsPage_Input {
background-color: transparent;
border: none;
color: var(--text-primary-color);
font-size: 20px;
width: 100%;
padding: 11px;
&:focus, &:active {
outline: none;
}
}
.ItemsPage_Input::placeholder {
color: var(--text-secondary-color);
opacity: 1;
}
.ItemsPage_List {
display: grid;
gap: 15px 15px;
grid-template-columns: repeat(15, 100px);
margin-bottom: 28px;
overflow-y: scroll;
}
.ItemsPage_Card {
display: flex;
width: 100%;
max-width: 300px;
min-height: 300px;
max-height: 700px;
align-self: center;
}

View File

@ -0,0 +1,44 @@
.ScenesPage {
display: flex;
height: 100%;
width: 100%;
background-color: var(--background-color);
flex-direction: column;
padding: 24px;
}
.ScenesPage_Title {
max-width: 180px;
max-height: 60px;
font-size: 48px;
font-weight: bold;
text-align: center;
margin-bottom: 30px;
}
.ScenesPage_List {
display: flex;
flex-direction: column;
gap: 15px;
margin-bottom: 28px;
overflow-y: scroll;
}
.ScenesPage_Button {
width: 94px;
height: 34px;
margin: 0;
border-radius: 10px;
border: transparent;
font-size: 20px;
color: var(--text-primary-color);
background-color: var(--background-color);
}

View File

@ -0,0 +1,4 @@
.Content {
width: 100%;
height: 100%;
}

View File

@ -0,0 +1,67 @@
.SideBar {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
max-width: 300px;
background-color: var(--secondary-color);
gap: 40px;
}
.SideBar_Title {
margin-top: 42px;
line-height: 41px;
font-size: 34px;
max-width: 256px;
max-height: 128px;
text-align: center;
align-self: center;
}
.SideBar_Buttons {
display: flex;
flex-direction: column;
padding-left: 27px;
gap: 15px;
}
.SideBar_Enter {
display: flex;
width: 100%;
height: 100%;
max-width: 250px;
max-height: 50px;
margin-bottom: 24px;
box-sizing: border-box;
align-self: center;
align-items: center;
border-radius: 10px;
background-color: var(--background-color);
}
.SideBar_Input {
background-color: transparent;
border: none;
color: var(--text-primary-color);
font-size: 20px;
width: 100%;
padding: 11px;
&:focus, &:active {
outline: none;
}
}
.SideBar_Input::placeholder {
color: var(--text-secondary-color);
opacity: 1;
}

View File

@ -0,0 +1,56 @@
.Card {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
max-width: 1510px;
max-height: 100px;
border-radius: 15px;
padding: 10px;
box-sizing: border-box;
background-color: var(--secondary-color);
}
.Card_Content {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.Card_Header {
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
gap: 15px;
align-items: center;
}
.Card_Title {
font-size: 32px;
font-weight: bold;
}
.Card_Alternate {
font-size: 24px;
}
.Card_Description {
color: var(--text-primary-color);
overflow-y: scroll;
max-height: 24px;
}
.Card_Button {
display: flex;
margin-right: 13px;
align-self: center;
justify-content: center;
}

View File

@ -0,0 +1,36 @@
.Character {
display: flex;
flex-direction: column;
max-width: 100px;
max-height: 125px;
border-radius: 15px;
height: 100%;
overflow: hidden;
}
.Character_Icon {
width: 100%;
height: 100%;
max-width: 96px;
max-height: 96px;
}
.Character_Label {
display: flex;
justify-content: center;
align-items: center;
background-color: var(--secondary-color);
max-width: 100px;
height: 30px;
p {
font-size: 18px;
text-align: center;
}
}

View File

@ -0,0 +1,29 @@
.HomeButton {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
max-width: 256px;
max-height: 256px;
background-color: var(--secondary-color);
align-items: center;
justify-content: center;
gap: 20px;
border-radius: 10px;
}
.HomeButton_Icon {
max-width: 128px;
max-height: 128px;
}
.HomeButton_Label {
font-size: 34px;
line-height: 44px;
text-align: center;
font-style: normal;
}

View File

@ -0,0 +1,143 @@
.ItemCard {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
height: 100%;
max-width: 300px;
min-height: 300px;
max-height: 700px;
padding: 20px;
box-sizing: border-box;
border-radius: 10px;
background-color: var(--accent-color);
}
.ItemCard_Content {
display: flex;
gap: 10px;
flex-direction: column;
}
.ItemCard_Header {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.ItemCard_Info {
display: flex;
flex-direction: column;
gap: 10px;
:nth-child(1) {
font-weight: bold;
font-size: 20px;
max-width: 170px;
max-height: 60px;
color: var(--text-primary-color);
}
:nth-child(2) {
font-size: 16px;
color: var(--text-primary-color);
}
}
.ItemCard_Icon {
width: 64px;
height: 64px
}
.ItemCard_Description {
display: flex;
flex-direction: column;
max-width: 250px;
max-height: 460px;
p {
font-size: 14px;
color: var(--text-primary-color);
}
}
.ItemCard_Actions {
display: flex;
flex-direction: column;
gap: 5px;
padding-top: 10px;
}
.ItemCard_Counter {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
height: 100%;
max-width: 260px;
max-height: 46px;
border-radius: 10px;
padding: 0 13px 0 13px;
box-sizing: border-box;
align-items: center;
background-color: var(--secondary-color);
}
.ItemCard_Operation {
user-select: none;
display: flex;
width: 30px;
height: 20px;
font-size: 24px;
align-items: center;
justify-content: center;
color: var(--text-primary-color);
background-color: var(--background-color);
}
.ItemCard_Count {
max-width: 105px;
height: 48px;
font-size: 24px;
text-align: center;
background-color: transparent;
color: var(--text-primary-color);
border: transparent;
}
.ItemCard_Count:focus {
outline: none;
}
.ItemCard_Submit {
width: 100%;
height: 46px;
max-width: 260px;
border-radius: 10px;
text-align: center;
justify-content: center;
border: transparent;
font-size: 24px;
color: var(--text-primary-color);
background-color: var(--secondary-color);
}

View File

@ -0,0 +1,40 @@
.MiniCard {
display: flex;
width: 64px;
height: 64px;
overflow: hidden;
justify-content: center;
}
.MiniCard_Background {
display: flex;
align-items: center;
max-width: 64px;
max-height: 64px;
border-radius: 10px;
background-color: var(--secondary-color);
}
.MiniCard_Icon {
max-width: 64px;
max-height: 64px;
object-fit: scale-down;
border-radius: 10px;
}
.MiniCard_Label {
width: 64px;
max-height: 64px;
text-align: center;
font-size: 12px;
color: var(--text-primary-color);
}
.MiniCard_Info {
position: absolute;
display: flex;
}

View File

@ -0,0 +1,26 @@
.SideBarButton {
display: flex;
flex-direction: row;
gap: 15px;
width: 100%;
height: 64px;
max-width: 300px;
max-height: 64px;
align-items: center;
}
.SideBarButton_Icon {
max-width: 64px;
max-height: 64px;
}
.SideBarButton_Label {
font-size: 22px;
line-height: 29px;
font-style: normal;
max-width: 220px;
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127.14 96.36"><defs><style>.cls-1{fill:#fff;}</style></defs><g id="图层_2" data-name="图层 2"><g id="Discord_Logos" data-name="Discord Logos"><g id="Discord_Logo_-_Large_-_White" data-name="Discord Logo - Large - White"><path class="cls-1" d="M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z"/></g></g></g></svg>

After

Width:  |  Height:  |  Size: 985 B

18
src/handbook/src/main.tsx Normal file
View File

@ -0,0 +1,18 @@
import React from "react";
import { createRoot } from "react-dom/client";
import * as data from "@backend/data";
import * as events from "@backend/events";
import App from "@ui/App";
// Call initial setup functions.
data.setup();
events.setup();
// Render the application.
createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<App />
</React.StrictMode>
);

View File

@ -0,0 +1,50 @@
import React from "react";
import SideBar from "@views/SideBar";
import Content from "@views/Content";
import type { Page } from "@backend/types";
import { isPage } from "@backend/types";
import "@css/App.scss";
import "@css/Text.scss";
// Based on the design at: https://www.figma.com/file/PDeAVDkTDF5vvUGGdaIZ39/GM-Handbook.
// Currently designed by: Magix.
interface IState {
initial: Page | null;
}
class App extends React.Component<{}, IState> {
constructor(props: any) {
super(props);
// Check if the window's href is a page.
let targetPage = null;
const page = window.location.href.split("/").pop();
console.log(page);
if (page != undefined && page != "") {
// Convert the page to a Page type.
const pageName = page.charAt(0).toUpperCase() + page.slice(1);
// Check if the page is a valid page.
if (isPage(pageName)) targetPage = pageName as Page;
}
this.state = {
initial: targetPage as Page | null
};
}
render() {
return (
<div className={"App"}>
<SideBar />
<Content initial={this.state.initial} />
</div>
);
}
}
export default App;

View File

@ -0,0 +1,88 @@
import React from "react";
import { List as _List, ListProps, ListRowProps } from "react-virtualized/dist/es/List";
import { AutoSizer as _AutoSizer, AutoSizerProps } from "react-virtualized/dist/es/AutoSizer";
const List = _List as unknown as React.FC<ListProps>;
const AutoSizer = _AutoSizer as unknown as React.FC<AutoSizerProps>;
import "@css/components/VirtualizedGrid.scss";
interface IProps<T> {
list: T[];
render: (item: T) => React.ReactNode;
itemHeight: number;
itemsPerRow?: number;
gap?: number;
itemGap?: number;
}
interface IState {
scrollTop: number;
}
class VirtualizedGrid<T> extends React.Component<IProps<T>, IState> {
constructor(props: IProps<T>) {
super(props);
this.state = {
scrollTop: 0
};
}
/**
* Renders a row of items.
*/
private rowRender(props: ListRowProps): React.ReactNode {
const items: React.ReactNode[] = [];
// Calculate the items to render.
const perRow = this.props.itemsPerRow ?? 10;
for (let i = 0; i < perRow; i++) {
const itemIndex = props.index * perRow + i;
if (itemIndex < this.props.list.length) {
items.push(this.props.render(this.props.list[itemIndex]));
}
}
return (
<div
key={props.key}
style={{
...props.style,
gap: this.props.itemGap ?? 0
}}
className={"GridRow"}
>
{items.map((item, index) => (
<div key={index}>{item}</div>
))}
<div style={{ height: this.props.gap ?? 0 }} />
</div>
);
}
render() {
const { list, itemHeight, itemsPerRow } = this.props;
return (
<AutoSizer>
{({ height, width }) => (
<List
height={height - 150}
width={width}
rowHeight={itemHeight + (this.props.gap ?? 0)}
rowCount={Math.ceil(list.length / (itemsPerRow ?? 10))}
rowRenderer={this.rowRender.bind(this)}
scrollTop={this.state.scrollTop}
onScroll={(e) => this.setState({ scrollTop: e.scrollTop })}
/>
)}
</AutoSizer>
);
}
}
export default VirtualizedGrid;

View File

@ -0,0 +1,39 @@
import React from "react";
import Character from "@app/ui/widgets/Character";
import type { Avatar } from "@backend/types";
import { listAvatars } from "@backend/data";
import { grantAvatar } from "@backend/server";
import "@css/pages/AvatarsPage.scss";
class AvatarsPage extends React.PureComponent {
/**
* Grants the avatar to the user.
*
* @param avatar The avatar to grant.
* @private
*/
private async grantAvatar(avatar: Avatar): Promise<void> {
console.log(await grantAvatar(avatar.id));
}
render() {
return (
<div className={"AvatarsPage"}>
<h1 className={"AvatarsPage_Title"}>Characters</h1>
<div className={"AvatarsPage_List"}>
{listAvatars().map((avatar) =>
avatar.id > 11000000 ? undefined : (
<Character key={avatar.id} data={avatar} onClick={this.grantAvatar.bind(this, avatar)} />
)
)}
</div>
</div>
);
}
}
export default AvatarsPage;

View File

@ -0,0 +1,33 @@
import React from "react";
import Card from "@widgets/Card";
import { listCommands } from "@backend/data";
import "@css/pages/CommandsPage.scss";
class CommandsPage extends React.PureComponent {
render() {
return (
<div className={"CommandsPage"}>
<h1 className={"CommandsPage_Title"}>Commands</h1>
<div className={"CommandsPage_List"}>
{listCommands().map((command) => (
<Card
key={command.name[0]}
title={command.name[0]}
alternate={
command.name.length == 1 ? undefined : `(aka /${command.name.slice(1).join(", /")})`
}
description={command.description}
height={75}
/>
))}
</div>
</div>
);
}
}
export default CommandsPage;

View File

@ -0,0 +1,153 @@
import React, { ChangeEvent } from "react";
import MiniCard from "@widgets/MiniCard";
import VirtualizedGrid from "@components/VirtualizedGrid";
import { Entity, ItemCategory } from "@backend/types";
import type { Entity as EntityType, EntityInfo } from "@backend/types";
import { getEntities } from "@backend/data";
import { entityIcon, fetchEntityData } from "@app/utils";
import "@css/pages/EntitiesPage.scss";
import EntityCard from "@widgets/EntityCard";
interface IState {
filters: ItemCategory[];
search: string;
selected: EntityType | null;
selectedInfo: EntityInfo | null;
}
class EntitiesPage extends React.Component<{}, IState> {
constructor(props: {}) {
super(props);
this.state = {
filters: [],
search: "",
selected: null,
selectedInfo: null
};
}
/**
* Should the entity be shown?
*
* @param entity The entity.
* @private
*/
private showEntity(entity: Entity): boolean {
// Check if the entity's name starts with N/A.
if (entity.name.includes("[N/A]")) return false;
return entity.id > 0;
}
/**
* Gets the items to render.
* @private
*/
private getEntities(): EntityType[] {
let entities: EntityType[] = [];
// Add items based on filters.
const filters = this.state.filters;
if (filters.length == 0) {
entities = getEntities();
} else {
for (const filter of filters) {
// Remove duplicate items.
entities = entities.filter((item, index) => {
return entities.indexOf(item) == index;
});
}
}
// Filter out items that don't match the search.
const search = this.state.search.toLowerCase();
if (search != "") {
entities = entities.filter((item) => {
return item.name.toLowerCase().includes(search);
});
}
return entities;
}
/**
* Invoked when the search input changes.
*
* @param event The event.
* @private
*/
private onChange(event: ChangeEvent<HTMLInputElement>): void {
this.setState({ search: event.target.value });
}
/**
* Sets the selected entity.
*
* @param entity The entity.
* @private
*/
private async setSelectedItem(entity: EntityType): Promise<void> {
let data: EntityInfo | null = null;
try {
data = await fetchEntityData(entity);
} catch {}
this.setState({
selected: entity,
selectedInfo: data
});
}
render() {
const entities = this.getEntities();
return (
<div className={"EntitiesPage"}>
<div className={"EntitiesPage_Content"}>
<div className={"EntitiesPage_Header"}>
<h1 className={"EntitiesPage_Title"}>Monsters</h1>
<div className={"EntitiesPage_Search"}>
<input
type={"text"}
className={"EntitiesPage_Input"}
placeholder={"Search..."}
onChange={this.onChange.bind(this)}
/>
</div>
</div>
{entities.length > 0 ? (
<VirtualizedGrid
list={entities.filter((entity) => this.showEntity(entity))}
itemHeight={64}
itemsPerRow={18}
gap={5}
itemGap={5}
render={(entity) => (
<MiniCard
key={entity.id}
data={entity}
icon={entityIcon(entity)}
onClick={() => this.setSelectedItem(entity)}
/>
)}
/>
) : undefined}
</div>
<div className={"EntitiesPage_Card"}>
<EntityCard entity={this.state.selected} info={this.state.selectedInfo} />
</div>
</div>
);
}
}
export default EntitiesPage;

View File

@ -0,0 +1,66 @@
import React from "react";
import HomeButton from "@widgets/HomeButton";
import { ReactComponent as DiscordLogo } from "@icons/discord.svg";
import "@css/pages/HomePage.scss";
class HomePage extends React.Component<any, any> {
constructor(props: any) {
super(props);
}
render() {
return (
<div className={"HomePage"}>
<div className={"HomePage_Top"}>
<h1 className={"HomePage_Title"}>Welcome back, Traveler~</h1>
<div className={"HomePage_Buttons"}>
<HomeButton name={"Commands"} anchor={"Commands"} />
<HomeButton name={"Characters"} anchor={"Avatars"} />
<HomeButton name={"Items"} anchor={"Items"} />
<HomeButton name={"Entities"} anchor={"Entities"} />
<HomeButton name={"Scenes"} anchor={"Scenes"} />
</div>
<div className={"HomePage_Buttons"}>
<HomeButton name={"Quests"} anchor={"Home"} />
<HomeButton name={"Achievements"} anchor={"Home"} />
</div>
</div>
<div className={"HomePage_Bottom"}>
<div className={"HomePage_Box HomePage_Disclaimer"}>
<div>
<p>This tool is not affiliated with HoYoverse.</p>
<p>Genshin Impact, game content and materials are</p>
<p>trademarks and copyrights of HoYoverse.</p>
</div>
<div className={"HomePage_Discord"}>
<DiscordLogo />
<p>Join the Community!</p>
</div>
</div>
<div className={"HomePage_Text"}>
<div className={"HomePage_Credits"}>
<p>Credits</p>
<p>(hover to see info)</p>
</div>
<div className={"HomePage_Links"}>
<a href={"https://paimon.moe"}>paimon.moe</a>
<a href={"https://gitlab.com/Dimbreath/AnimeGameData"}>Anime Game Data</a>
<a href={"https://genshin-impact.fandom.com"}>Genshin Impact Wiki</a>
</div>
</div>
</div>
</div>
);
}
}
export default HomePage;

View File

@ -0,0 +1,157 @@
import React, { ChangeEvent } from "react";
import MiniCard from "@widgets/MiniCard";
import ItemCard from "@widgets/ItemCard";
import VirtualizedGrid from "@components/VirtualizedGrid";
import { ItemCategory } from "@backend/types";
import type { Item as ItemType, ItemInfo } from "@backend/types";
import { getItems, sortedItems } from "@backend/data";
import { fetchItemData, itemIcon } from "@app/utils";
import "@css/pages/ItemsPage.scss";
interface IState {
filters: ItemCategory[];
search: string;
selected: ItemType | null;
selectedInfo: ItemInfo | null;
}
class ItemsPage extends React.Component<{}, IState> {
constructor(props: {}) {
super(props);
this.state = {
filters: [],
search: "",
selected: null,
selectedInfo: null
};
}
/**
* Gets the items to render.
* @private
*/
private getItems(): ItemType[] {
let items: ItemType[] = [];
// Add items based on filters.
const filters = this.state.filters;
if (filters.length == 0) {
items = getItems();
} else {
for (const filter of filters) {
// Add items from the category.
items = items.concat(sortedItems[filter]);
// Remove duplicate items.
items = items.filter((item, index) => {
return items.indexOf(item) == index;
});
}
}
// Filter out items that don't match the search.
const search = this.state.search.toLowerCase();
if (search != "") {
items = items.filter((item) => {
return item.name.toLowerCase().includes(search);
});
}
return items;
}
/**
* Invoked when the search input changes.
*
* @param event The event.
* @private
*/
private onChange(event: ChangeEvent<HTMLInputElement>): void {
this.setState({ search: event.target.value });
}
/**
* Should the item be showed?
*
* @param item The item.
* @private
*/
private showItem(item: ItemType): boolean {
// Check if the item has an icon.
if (item.icon.length == 0) return false;
// Check if the item is a TCG card.
if (item.icon.includes("Gcg")) return false;
return item.id > 0;
}
/**
* Sets the selected item.
*
* @param item The item.
* @private
*/
private async setSelectedItem(item: ItemType): Promise<void> {
let data: ItemInfo | null = null;
try {
data = await fetchItemData(item);
} catch {}
this.setState({
selected: item,
selectedInfo: data
});
}
render() {
const items = this.getItems();
return (
<div className={"ItemsPage"}>
<div className={"ItemsPage_Content"}>
<div className={"ItemsPage_Header"}>
<h1 className={"ItemsPage_Title"}>Items</h1>
<div className={"ItemsPage_Search"}>
<input
type={"text"}
className={"ItemsPage_Input"}
placeholder={"Search..."}
onChange={this.onChange.bind(this)}
/>
</div>
</div>
{items.length > 0 ? (
<VirtualizedGrid
list={items.filter((item) => this.showItem(item))}
itemHeight={64}
itemsPerRow={18}
gap={5}
itemGap={5}
render={(item) => (
<MiniCard
key={item.id}
data={item}
icon={itemIcon(item)}
onClick={() => this.setSelectedItem(item)}
/>
)}
/>
) : undefined}
</div>
<div className={"ItemsPage_Card"}>
<ItemCard item={this.state.selected} info={this.state.selectedInfo} />
</div>
</div>
);
}
}
export default ItemsPage;

View File

@ -0,0 +1,71 @@
import React from "react";
import Card from "@widgets/Card";
import { SceneType } from "@backend/types";
import { getScenes } from "@backend/data";
import "@css/pages/ScenesPage.scss";
/**
* Converts a scene type to a string.
*
* @param type The scene type.
*/
function sceneTypeToString(type: SceneType): string {
switch (type) {
default:
return "Unknown";
case SceneType.None:
return "None";
case SceneType.World:
return "World";
case SceneType.Activity:
return "Activity";
case SceneType.Dungeon:
return "Dungeon";
case SceneType.Room:
return "Room";
case SceneType.HomeRoom:
return "Home Room";
case SceneType.HomeWorld:
return "Home World";
}
}
class ScenesPage extends React.PureComponent {
/**
* Teleports the player to the specified scene.
* @private
*/
private async teleport(): Promise<void> {
// TODO: Implement teleporting.
}
render() {
return (
<div className={"ScenesPage"}>
<h1 className={"ScenesPage_Title"}>Scenes</h1>
<div className={"ScenesPage_List"}>
{getScenes().map((command) => (
<Card
key={command.identifier}
title={command.identifier}
alternate={`ID: ${command.id} | ${sceneTypeToString(command.type)}`}
button={
<button className={"ScenesPage_Button"} onClick={this.teleport.bind(this)}>
Teleport
</button>
}
rightOffset={13}
height={75}
/>
))}
</div>
</div>
);
}
}
export default ScenesPage;

View File

@ -0,0 +1,70 @@
import React from "react";
import HomePage from "@pages/HomePage";
import CommandsPage from "@pages/CommandsPage";
import AvatarsPage from "@pages/AvatarsPage";
import ItemsPage from "@pages/ItemsPage";
import EntitiesPage from "@pages/EntitiesPage";
import ScenesPage from "@pages/ScenesPage";
import type { Page } from "@backend/types";
import { addNavListener, removeNavListener } from "@backend/events";
import "@css/views/Content.scss";
interface IProps {
initial?: Page | null;
}
interface IState {
current: Page;
}
class Content extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
current: props.initial ?? "Home"
};
}
/**
* Navigates to the specified page.
*
* @param page The page to navigate to.
* @private
*/
private navigate(page: Page): void {
this.setState({ current: page });
}
componentDidMount() {
addNavListener(this.navigate.bind(this));
}
componentWillUnmount() {
removeNavListener(this.navigate.bind(this));
}
render() {
switch (this.state.current) {
default:
return undefined;
case "Home":
return <HomePage />;
case "Commands":
return <CommandsPage />;
case "Avatars":
return <AvatarsPage />;
case "Items":
return <ItemsPage />;
case "Entities":
return <EntitiesPage />;
case "Scenes":
return <ScenesPage />;
}
}
}
export default Content;

View File

@ -0,0 +1,78 @@
import React, { ChangeEvent } from "react";
import SideBarButton from "@app/ui/widgets/SideBarButton";
import { navigate } from "@app/backend/events";
import "@css/views/SideBar.scss";
import { setTargetPlayer } from "@backend/server";
interface IState {
uid: string | null;
}
class SideBar extends React.Component<{}, IState> {
constructor(props: {}) {
super(props);
this.state = {
uid: null
};
}
/**
* Invoked when the UID input changes.
*
* @param event The event.
* @private
*/
private onChange(event: ChangeEvent<HTMLInputElement>): void {
const input = event.target.value;
const uid = input == "" ? null : input;
if (uid && uid.length > 10) return;
this.setState({ uid });
setTargetPlayer(parseInt(uid ?? "0"));
}
render() {
return (
<div className={"SideBar"}>
<h1 className={"SideBar_Title"} onClick={() => navigate("Home")}>
The Ultimate Anime Game Handbook
</h1>
<div
style={{
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
height: "100%"
}}
>
<div className={"SideBar_Buttons"}>
<SideBarButton name={"Commands"} anchor={"Commands"} />
<SideBarButton name={"Characters"} anchor={"Avatars"} />
<SideBarButton name={"Items"} anchor={"Items"} />
<SideBarButton name={"Entities"} anchor={"Entities"} />
<SideBarButton name={"Scenes"} anchor={"Scenes"} />
<SideBarButton name={"Quests"} anchor={"Home"} />
<SideBarButton name={"Achievements"} anchor={"Home"} />
</div>
<div className={"SideBar_Enter"}>
<input
type={"text"}
className={"SideBar_Input"}
placeholder={"Enter UID..."}
value={this.state.uid ?? undefined}
onChange={this.onChange.bind(this)}
/>
</div>
</div>
</div>
);
}
}
export default SideBar;

View File

@ -0,0 +1,64 @@
import React from "react";
import "@css/widgets/Card.scss";
interface IProps {
title: string;
alternate?: string;
description?: string | string[];
height?: number | string;
button?: React.ReactNode;
rightOffset?: number;
onClick?: () => void;
onOver?: () => void;
onOut?: () => void;
}
class Card extends React.PureComponent<IProps> {
constructor(props: IProps) {
super(props);
}
render() {
return (
<div
className={"Card"}
onClick={this.props.onClick}
onMouseOver={this.props.onOver}
onMouseOut={this.props.onOut}
style={{ height: this.props.height }}
>
<div className={"Card_Content"}>
<div className={"Card_Header"}>
<p className={"Card_Title"}>{this.props.title}</p>
{this.props.alternate && <p className={"Card_Alternate"}>{this.props.alternate}</p>}
</div>
<div style={{ alignItems: "center" }}>
{this.props.description ? (
Array.isArray(this.props.description) ? (
this.props.description.map((line, index) => (
<p className={"Card_Description"} key={index}>
{line}
</p>
))
) : (
<p className={"Card_Description"}>{this.props.description}</p>
)
) : undefined}
</div>
</div>
{this.props.button ? (
<div className={"Card_Button"} style={{ marginRight: this.props.rightOffset ?? 0 }}>
{this.props.button}
</div>
) : undefined}
</div>
);
}
}
export default Card;

View File

@ -0,0 +1,57 @@
import React from "react";
import type { Avatar } from "@backend/types";
import { colorFor, formatAvatarName } from "@app/utils";
import "@css/widgets/Character.scss";
// Image base URL: https://paimon.moe/images/characters/(name).png
const ignored = [
10000001 // Kate
];
const nameSwitch: { [key: number]: string } = {
10000005: "Lumine",
10000007: "Aether"
};
interface IProps {
data: Avatar;
onClick?: () => void;
}
class Character extends React.PureComponent<IProps> {
constructor(props: IProps) {
super(props);
}
render() {
const { name, quality, id } = this.props.data;
const qualityColor = colorFor(quality);
// Check if the avatar is blacklisted.
if (ignored.includes(id)) return undefined;
return (
<div
className={"Character"}
style={{ backgroundColor: `var(${qualityColor})` }}
onClick={this.props.onClick}
>
<img
className={"Character_Icon"}
alt={name}
src={`https://paimon.moe/images/characters/${formatAvatarName(name, id)}.png`}
/>
<div className={"Character_Label"}>
<p>{nameSwitch[id] ?? name}</p>
</div>
</div>
);
}
}
export default Character;

View File

@ -0,0 +1,162 @@
import React from "react";
import type { Entity as EntityType, EntityInfo } from "@backend/types";
import { entityIcon } from "@app/utils";
import "@css/widgets/ItemCard.scss";
/**
* Converts a description string into a list of paragraphs.
*
* @param description The description to convert.
*/
function toDescription(description: string | undefined): JSX.Element[] {
if (!description) return [];
return description.split("\\n").map((line, index) => {
return <p key={index}>{line}</p>;
});
}
interface IProps {
entity: EntityType | null;
info: EntityInfo | null;
}
interface IState {
icon: boolean;
count: number | string;
}
const defaultState = {
icon: true,
count: 1
};
class EntityCard extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = defaultState;
}
/**
* Updates the count of the item.
*
* @param event The change event.
* @private
*/
private updateCount(event: React.ChangeEvent<HTMLInputElement>) {
const value = event.target.value;
if (isNaN(parseInt(value)) && value.length > 1) return;
this.setState({ count: value });
}
/**
* Adds to the count of the entity.
*
* @param positive Is the count being added or subtracted?
* @param multiple Is the count being multiplied by 10?
* @private
*/
private addCount(positive: boolean, multiple: boolean) {
let { count } = this.state;
if (count === "") count = 1;
if (typeof count == "string") count = parseInt(count);
if (count < 1) count = 1;
let increment = 1;
if (!positive) increment = -1;
if (multiple) increment *= 10;
count = Math.max(1, count + increment);
this.setState({ count });
}
/**
* Summons the entity at the connected player's position.
* @private
*/
private async summonAtPlayer(): Promise<void> {
// TODO: Implement server access.
}
componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>, snapshot?: any) {
if (this.props.entity != prevProps.entity) {
this.setState(defaultState);
}
}
render() {
const { entity, info } = this.props;
const data = info?.data;
return entity ? (
<div className={"ItemCard"}>
<div className={"ItemCard_Content"}>
<div className={"ItemCard_Header"}>
<div className={"ItemCard_Info"}>
<p>{data?.name ?? entity.name}</p>
<p>{data?.type ?? ""}</p>
</div>
{this.state.icon && (
<img
className={"ItemCard_Icon"}
alt={entity.name}
src={entityIcon(entity)}
onError={() => this.setState({ icon: false })}
/>
)}
</div>
<div className={"ItemCard_Description"}>{toDescription(data?.description)}</div>
</div>
<div className={"ItemCard_Actions"}>
<div className={"ItemCard_Counter"}>
<div
onClick={() => this.addCount(false, false)}
onContextMenu={(e) => {
e.preventDefault();
this.addCount(false, true);
}}
className={"ItemCard_Operation"}
>
-
</div>
<input
type={"text"}
value={this.state.count}
className={"ItemCard_Count"}
onChange={this.updateCount.bind(this)}
onBlur={() => {
if (this.state.count == "") {
this.setState({ count: 1 });
}
}}
/>
<div
onClick={() => this.addCount(true, false)}
onContextMenu={(e) => {
e.preventDefault();
this.addCount(true, true);
}}
className={"ItemCard_Operation"}
>
+
</div>
</div>
<button className={"ItemCard_Submit"} onClick={this.summonAtPlayer.bind(this)}>
Summon
</button>
</div>
</div>
) : undefined;
}
}
export default EntityCard;

View File

@ -0,0 +1,37 @@
import React from "react";
import type { Page } from "@backend/types";
import { navigate } from "@backend/events";
import "@css/widgets/HomeButton.scss";
interface IProps {
name: string;
anchor: Page;
}
class HomeButton extends React.PureComponent<IProps> {
constructor(props: IProps) {
super(props);
}
/**
* Redirects the user to the specified anchor.
* @private
*/
private redirect(): void {
navigate(this.props.anchor);
}
render() {
return (
<div className={"HomeButton"} onClick={() => this.redirect()}>
<img className={"HomeButton_Icon"} src={"https://dummyimage.com/128x128"} alt={this.props.name} />
<p className={"HomeButton_Label"}>{this.props.name}</p>
</div>
);
}
}
export default HomeButton;

View File

@ -0,0 +1,167 @@
import React from "react";
import type { Item as ItemType, ItemInfo } from "@backend/types";
import { itemTypeToString } from "@backend/types";
import { itemIcon } from "@app/utils";
import { giveItem } from "@backend/server";
import "@css/widgets/ItemCard.scss";
/**
* Converts a description string into a list of paragraphs.
*
* @param description The description to convert.
*/
function toDescription(description: string | undefined): JSX.Element[] {
if (!description) return [];
return description.split("\\n").map((line, index) => {
return <p key={index}>{line}</p>;
});
}
interface IProps {
item: ItemType | null;
info: ItemInfo | null;
}
interface IState {
icon: boolean;
count: number | string;
}
const defaultState = {
icon: true,
count: 1
};
class ItemCard extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = defaultState;
}
/**
* Updates the count of the item.
*
* @param event The change event.
* @private
*/
private updateCount(event: React.ChangeEvent<HTMLInputElement>) {
const value = event.target.value;
if (isNaN(parseInt(value)) && value.length > 1) return;
this.setState({ count: value });
}
/**
* Adds to the count of the item.
*
* @param positive Is the count being added or subtracted?
* @param multiple Is the count being multiplied by 10?
* @private
*/
private addCount(positive: boolean, multiple: boolean) {
let { count } = this.state;
if (count === "") count = 1;
if (typeof count == "string") count = parseInt(count);
if (count < 1) count = 1;
let increment = 1;
if (!positive) increment = -1;
if (multiple) increment *= 10;
count = Math.max(1, count + increment);
this.setState({ count });
}
/**
* Adds the item to the player's connected inventory.
* @private
*/
private async addToInventory(): Promise<void> {
await giveItem(
this.props.item?.id ?? 102,
typeof this.state.count == "string" ? parseInt(this.state.count) : this.state.count
);
}
componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>, snapshot?: any) {
if (this.props.item != prevProps.item) {
this.setState(defaultState);
}
}
render() {
const { item, info } = this.props;
const data = info?.data;
return item ? (
<div className={"ItemCard"}>
<div className={"ItemCard_Content"}>
<div className={"ItemCard_Header"}>
<div className={"ItemCard_Info"}>
<p>{data?.name ?? item.name}</p>
<p>{data?.type ?? itemTypeToString(item.type)}</p>
</div>
{this.state.icon && (
<img
className={"ItemCard_Icon"}
alt={item.name}
src={itemIcon(item)}
onError={() => this.setState({ icon: false })}
/>
)}
</div>
<div className={"ItemCard_Description"}>{toDescription(data?.description)}</div>
</div>
<div className={"ItemCard_Actions"}>
<div className={"ItemCard_Counter"}>
<div
onClick={() => this.addCount(false, false)}
onContextMenu={(e) => {
e.preventDefault();
this.addCount(false, true);
}}
className={"ItemCard_Operation"}
>
-
</div>
<input
type={"text"}
value={this.state.count}
className={"ItemCard_Count"}
onChange={this.updateCount.bind(this)}
onBlur={() => {
if (this.state.count == "") {
this.setState({ count: 1 });
}
}}
/>
<div
onClick={() => this.addCount(true, false)}
onContextMenu={(e) => {
e.preventDefault();
this.addCount(true, true);
}}
className={"ItemCard_Operation"}
>
+
</div>
</div>
<button className={"ItemCard_Submit"} onClick={this.addToInventory.bind(this)}>
Add to Inventory
</button>
</div>
</div>
) : undefined;
}
}
export default ItemCard;

View File

@ -0,0 +1,77 @@
import React from "react";
import { itemIcon } from "@app/utils";
import "@css/widgets/MiniCard.scss";
interface IProps {
data: { name: string };
icon: string;
onClick?: () => void;
}
interface IState {
popout: boolean;
icon: boolean;
loaded: boolean;
}
class MiniCard extends React.Component<IProps, IState> {
loading: number | any;
constructor(props: IProps) {
super(props);
this.state = {
popout: false,
icon: true,
loaded: false
};
}
/**
* Replaces the icon with the item's name.
* @private
*/
private replaceIcon(): void {
this.setState({ icon: false, loaded: false });
}
private forceReplace(): void {
if (!this.state.loaded) this.replaceIcon();
}
componentDidMount() {
this.loading = setTimeout(this.forceReplace.bind(this), 1e3);
}
componentWillUnmount() {
clearTimeout(this.loading);
this.loading = null;
}
render() {
return (
<div className={"MiniCard"} onClick={this.props.onClick}>
<div className={"MiniCard_Background"}>
{this.state.icon && (
<img
className={"MiniCard_Icon"}
alt={this.props.data.name}
src={this.props.icon}
onError={this.replaceIcon.bind(this)}
onLoad={() => this.setState({ loaded: true })}
/>
)}
{(!this.state.loaded || !this.state.icon) && (
<p className={"MiniCard_Label"}>{this.props.data.name}</p>
)}
</div>
</div>
);
}
}
export default MiniCard;

View File

@ -0,0 +1,37 @@
import React from "react";
import type { Page } from "@backend/types";
import { navigate } from "@backend/events";
import "@css/widgets/SideBarButton.scss";
interface IProps {
name: string;
anchor: Page;
}
class SideBarButton extends React.PureComponent<IProps> {
constructor(props: IProps) {
super(props);
}
/**
* Redirects the user to the specified anchor.
* @private
*/
private redirect(): void {
navigate(this.props.anchor);
}
render() {
return (
<div className={"SideBarButton"} onClick={() => this.redirect()}>
<img className={"SideBarButton_Icon"} src={"https://dummyimage.com/128x128"} alt={this.props.name} />
<p className={"SideBarButton_Label"}>{this.props.name}</p>
</div>
);
}
}
export default SideBarButton;

136
src/handbook/src/utils.ts Normal file
View File

@ -0,0 +1,136 @@
import type { Entity, Item, EntityInfo, ItemInfo } from "@backend/types";
import { ItemType, Quality } from "@backend/types";
/**
* Fetches the name of the CSS variable for the quality.
*
* @param quality The quality of the item.
*/
export function colorFor(quality: Quality): string {
switch (quality) {
default:
return "--legendary-color";
case "EPIC":
return "--epic-color";
case "RARE":
return "--rare-color";
case "UNCOMMON":
return "--uncommon-color";
case "COMMON":
return "--common-color";
case "UNKNOWN":
return "--unknown-color";
}
}
/**
* Checks if a value is between two numbers.
*
* @param value The value to check.
* @param min The minimum value.
* @param max The maximum value.
*/
export function inRange(value: number, min: number, max: number): boolean {
return value >= min && value <= max;
}
/**
* Gets the path to the icon for an item.
* Uses the Project Amber API to get the icon.
*
* @param item The item to get the icon for.
*/
export function itemIcon(item: Item): string {
// Check if the item matches a special case.
if (inRange(item.id, 1001, 1099)) {
return `https://paimon.moe/images/characters/${formatAvatarName(item.name, item.id)}.png`;
}
switch (item.type) {
default:
return `https://api.ambr.top/assets/UI/UI_${item.icon}.png`;
case ItemType.Furniture:
return `https://api.ambr.top/assets/UI/furniture/UI_${item.icon}.png`;
case ItemType.Reliquary:
return `https://api.ambr.top/assets/UI/reliquary/UI_${item.icon}.png`;
}
}
/**
* Gets the path to the icon for an entity.
* Uses the Project Amber API to get the icon.
*
* @param entity The entity to get the icon for. Project Amber data required.
*/
export function entityIcon(entity: Entity): string {
return `https://api.ambr.top/assets/UI/monster/UI_MonsterIcon_${entity.internal}.png`;
}
/**
* Formats a character's name to fit with the reference name.
* Example: Hu Tao -> hu_tao
*
* @param name The character's name.
* @param id The character's ID.
*/
export function formatAvatarName(name: string, id: number): string {
// Check if a different name is used for the character.
if (refSwitch[id]) name = refSwitch[id];
return name.toLowerCase().replace(" ", "_");
}
const refSwitch: { [key: number]: string } = {
10000005: "traveler_anemo",
10000007: "traveler_geo"
};
/**
* Gets the route for an item type.
*
* @param type The type of the item.
*/
export function typeToRoute(type: ItemType): string {
switch (type) {
default:
return "material";
case ItemType.Furniture:
return "furniture";
case ItemType.Reliquary:
return "reliquary";
case ItemType.Weapon:
return "weapon";
}
}
/**
* Fetches the data for an item.
* Uses the Project Amber API to get the data.
*
* @route GET https://api.ambr.top/v2/EN/{type}/{id}
* @param item The item to fetch the data for.
*/
export async function fetchItemData(item: Item): Promise<ItemInfo> {
let url = `https://api.ambr.top/v2/EN/(type)/(id)`;
// Replace the type and ID in the URL.
url = url.replace("(type)", typeToRoute(item.type));
url = url.replace("(id)", item.id.toString());
// Fetch the data.
return fetch(url)
.then((res) => res.json())
.catch(() => {});
}
/**
* Fetches the data for an entity.
* Uses the Project Amber API to get the data.
*
* @route GET https://api.ambr.top/v2/en/monster/{id}
* @param entity The entity to fetch the data for.
*/
export async function fetchEntityData(entity: Entity): Promise<EntityInfo> {
return fetch(`https://api.ambr.top/v2/en/monster/${entity.id}`)
.then((res) => res.json())
.catch(() => {});
}

View File

@ -0,0 +1,35 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"@app/*": ["src/*"],
"@backend/*": ["src/backend/*"],
"@css/*": ["src/css/*"],
"@ui/*": ["src/ui/*"],
"@icons/*": ["src/icons/*"],
"@views/*": ["src/ui/views/*"],
"@pages/*": ["src/ui/pages/*"],
"@widgets/*": ["src/ui/widgets/*"],
"@components/*": ["src/ui/components/*"],
"@data/*": ["data/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": [
"vite.config.ts"
]
}

View File

@ -0,0 +1,25 @@
// noinspection JSUnusedGlobalSymbols
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import tsconfigPaths from "vite-tsconfig-paths";
import dsv from "@rollup/plugin-dsv";
import viteSvgr from "vite-plugin-svgr";
import { viteSingleFile } from "vite-plugin-singlefile";
import postcss from "./cfg/postcss.config.js";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [ react(), tsconfigPaths(), dsv(),
viteSvgr(), viteSingleFile() ],
css: { postcss },
optimizeDeps: {
exclude: [
"react-virtualization"
]
}
});

View File

@ -1,10 +1,14 @@
package emu.grasscutter;
import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.SparseSet;
import emu.grasscutter.utils.Utils;
import java.util.Arrays;
public final class GameConstants {
public static String VERSION = "3.6.0";
public static final boolean DEBUG = true;
public static final int DEFAULT_TEAMS = 4;
public static final int MAX_TEAMS = 10;
public static final int MAIN_CHARACTER_MALE = 10000005;
@ -28,9 +32,19 @@ public final class GameConstants {
"Avatar_Component_Initializer",
"Avatar_FallAnthem_Achievement_Listener"
};
public static final SparseSet ILLEGAL_WEAPONS = new SparseSet("""
10000-10008, 11411, 11506-11508, 12505, 12506, 12508, 12509,
13503, 13506, 14411, 14503, 14505, 14508, 15504-15506
""");
public static final SparseSet ILLEGAL_RELICS = new SparseSet("""
20001, 23300-23340, 23383-23385, 78310-78554, 99310-99554
""");
public static final SparseSet ILLEGAL_ITEMS = new SparseSet("""
100086, 100087, 100100-101000, 101106-101110, 101306, 101500-104000,
105001, 105004, 106000-107000, 107011, 108000, 109000-110000,
115000-130000, 200200-200899, 220050, 220054
""");
public static final int[] DEFAULT_ABILITY_HASHES =
Arrays.stream(DEFAULT_ABILITY_STRINGS).mapToInt(Utils::abilityHash).toArray();
public static final int DEFAULT_ABILITY_NAME = Utils.abilityHash("Default");
public static String VERSION = "3.6.0";
public static final boolean DEBUG = true;
}

View File

@ -21,6 +21,7 @@ import emu.grasscutter.server.http.HttpServer;
import emu.grasscutter.server.http.dispatch.DispatchHandler;
import emu.grasscutter.server.http.dispatch.RegionHandler;
import emu.grasscutter.server.http.documentation.DocumentationServerHandler;
import emu.grasscutter.server.http.documentation.HandbookHandler;
import emu.grasscutter.server.http.handlers.AnnouncementsHandler;
import emu.grasscutter.server.http.handlers.GachaHandler;
import emu.grasscutter.server.http.handlers.GenericHandler;
@ -136,6 +137,7 @@ public final class Grasscutter {
httpServer.addRouter(DispatchHandler.class);
httpServer.addRouter(GachaHandler.class);
httpServer.addRouter(DocumentationServerHandler.class);
httpServer.addRouter(HandbookHandler.class);
// Start servers.
var runMode = Grasscutter.getRunMode();

View File

@ -23,6 +23,7 @@ import java.util.Map;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;
import static emu.grasscutter.GameConstants.*;
import static emu.grasscutter.command.CommandHelpers.*;
@Command(
@ -42,18 +43,6 @@ public final class GiveCommand implements CommandHandler {
Map.entry(constellationRegex, GiveItemParameters::setConstellation),
Map.entry(skillLevelRegex, GiveItemParameters::setSkillLevel)
);
private static final SparseSet illegalWeaponIds = new SparseSet("""
10000-10008, 11411, 11506-11508, 12505, 12506, 12508, 12509,
13503, 13506, 14411, 14503, 14505, 14508, 15504-15506
""");
private static final SparseSet illegalRelicIds = new SparseSet("""
20001, 23300-23340, 23383-23385, 78310-78554, 99310-99554
""");
private static final SparseSet illegalItemIds = new SparseSet("""
100086, 100087, 100100-101000, 101106-101110, 101306, 101500-104000,
105001, 105004, 106000-107000, 107011, 108000, 109000-110000,
115000-130000, 200200-200899, 220050, 220054
""");
private static Avatar makeAvatar(GiveItemParameters param) {
return makeAvatar(param.avatarData, param.lvl, Avatar.getMinPromoteLevel(param.lvl), param.constellation, param.skillLevel);
@ -231,7 +220,7 @@ public final class GiveCommand implements CommandHandler {
for (ItemData itemdata : GameData.getItemDataMap().values()) {
int id = itemdata.getId();
if (id < 100_000) continue; // Nothing meaningful below this
if (illegalItemIds.contains(id)) continue;
if (ILLEGAL_ITEMS.contains(id)) continue;
if (itemdata.isEquip()) continue;
GameItem item = new GameItem(itemdata);
@ -251,7 +240,7 @@ public final class GiveCommand implements CommandHandler {
for (ItemData itemdata : GameData.getItemDataMap().values()) {
int id = itemdata.getId();
if (id < 11100 || id > 16000) continue; // All extant weapons are within this range
if (illegalWeaponIds.contains(id)) continue;
if (ILLEGAL_WEAPONS.contains(id)) continue;
if (!itemdata.isEquip()) continue;
if (itemdata.getItemType() != ItemType.ITEM_WEAPON) continue;
@ -333,7 +322,7 @@ public final class GiveCommand implements CommandHandler {
if (param.lvl < 0) param.lvl = 0;
if (param.lvl > 20) param.lvl = 20;
param.lvl += 1;
if (illegalRelicIds.contains(param.id))
if (ILLEGAL_RELICS.contains(param.id))
CommandHandler.sendTranslatedMessage(sender, "commands.give.illegal_relic");
} else {
// Suitable for Avatars and Weapons

View File

@ -10,6 +10,8 @@ import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.server.game.BaseGameSystem;
import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
@ -43,11 +45,11 @@ public class DungeonSystem extends BaseGameSystem {
var handlerClasses = reflections.getSubTypesOf(clazz);
for (var obj : handlerClasses) {
this.registerPacketHandler(map, obj);
this.registerHandler(map, obj);
}
}
public <T> void registerPacketHandler(Int2ObjectMap<T> map, Class<? extends T> handlerClass) {
public <T> void registerHandler(Int2ObjectMap<T> map, Class<? extends T> handlerClass) {
try {
DungeonValue opcode = handlerClass.getAnnotation(DungeonValue.class);
@ -178,5 +180,6 @@ public class DungeonSystem extends BaseGameSystem {
// Transfer player back to world
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
}
}

View File

@ -0,0 +1,173 @@
package emu.grasscutter.server.http.documentation;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.Grasscutter.ServerRunMode;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.server.http.Router;
import emu.grasscutter.utils.FileUtils;
import emu.grasscutter.utils.objects.HandbookBody;
import io.javalin.Javalin;
import io.javalin.http.Context;
import static emu.grasscutter.config.Configuration.HANDBOOK;
/** Handles requests for the new GM Handbook. */
public final class HandbookHandler implements Router {
private final byte[] handbook;
private final boolean serve;
/**
* Constructor for the handbook router.
* Enables serving the handbook if the handbook file is found.
*/
public HandbookHandler() {
this.handbook = FileUtils.readResource("/handbook.html");
this.serve = HANDBOOK.enable && this.handbook.length > 0;
}
@Override
public void applyRoutes(Javalin javalin) {
if (!this.serve) return;
// The handbook content. (built from src/handbook)
javalin.get("/handbook", this::serveHandbook);
// Handbook control routes.
javalin.post("/handbook/avatar", this::grantAvatar);
javalin.post("/handbook/item", this::giveItem);
}
/**
* @return True if the server can execute handbook commands.
*/
private boolean controlSupported() {
return HANDBOOK.enable &&
Grasscutter.getRunMode() == ServerRunMode.HYBRID;
}
/**
* Serves the handbook if it is found.
*
* @route GET /handbook
* @param ctx The Javalin request context.
*/
private void serveHandbook(Context ctx) {
if (!this.serve) {
ctx.status(500).result("Handbook not found.");
} else {
ctx.contentType("text/html").result(this.handbook);
}
}
/**
* Grants the avatar to the user.
*
* @route POST /handbook/avatar
* @param ctx The Javalin request context.
*/
private void grantAvatar(Context ctx) {
if (!this.controlSupported()) {
ctx.status(500).result("Handbook control not supported.");
return;
}
// Parse the request body into a class.
var request = ctx.bodyAsClass(HandbookBody.GrantAvatar.class);
// Validate the request.
if (request.getPlayer() == null || request.getAvatar() == null) {
ctx.status(400).result("Invalid request.");
return;
}
try {
// Parse the requested player.
var playerId = Integer.parseInt(request.getPlayer());
var player = Grasscutter.getGameServer().getPlayerByUid(playerId);
// Parse the requested avatar.
var avatarId = Integer.parseInt(request.getAvatar());
var avatarData = GameData.getAvatarDataMap().get(avatarId);
// Validate the request.
if (player == null || avatarData == null) {
ctx.status(400).result("Invalid player UID or avatar ID.");
return;
}
// Create the new avatar.
var avatar = new Avatar(avatarData);
avatar.setLevel(request.getLevel());
avatar.setPromoteLevel(Avatar.getMinPromoteLevel(avatar.getLevel()));
avatar.getSkillDepot().getSkillsAndEnergySkill().forEach(id ->
avatar.setSkillLevel(id, request.getTalentLevels()));
avatar.forceConstellationLevel(request.getConstellations());
avatar.recalcStats(true); avatar.save();
player.addAvatar(avatar); // Add the avatar.
ctx.json(HandbookBody.Response.builder()
.status(200)
.message("Avatar granted.")
.build());
} catch (NumberFormatException ignored) {
ctx.status(500).result("Invalid player UID or avatar ID.");
} catch (Exception exception) {
ctx.status(500).result("An error occurred while granting the avatar.");
Grasscutter.getLogger().debug("A handbook command error occurred.", exception);
}
}
/**
* Gives an item to the user.
*
* @route POST /handbook/item
* @param ctx The Javalin request context.
*/
private void giveItem(Context ctx) {
if (!this.controlSupported()) {
ctx.status(500).result("Handbook control not supported.");
return;
}
// Parse the request body into a class.
var request = ctx.bodyAsClass(HandbookBody.GiveItem.class);
// Validate the request.
if (request.getPlayer() == null || request.getItem() == null) {
ctx.status(400).result("Invalid request.");
return;
}
try {
// Parse the requested player.
var playerId = Integer.parseInt(request.getPlayer());
var player = Grasscutter.getGameServer().getPlayerByUid(playerId);
// Parse the requested item.
var itemId = Integer.parseInt(request.getItem());
var itemData = GameData.getItemDataMap().get(itemId);
// Validate the request.
if (player == null || itemData == null) {
ctx.status(400).result("Invalid player UID or item ID.");
return;
}
// Create the new item stack.
var itemStack = new GameItem(itemData, request.getAmount());
// Add the item to the inventory.
player.getInventory().addItem(itemStack, ActionReason.Gm);
ctx.json(HandbookBody.Response.builder()
.status(200)
.message("Item granted.")
.build());
} catch (NumberFormatException ignored) {
ctx.status(500).result("Invalid player UID or item ID.");
} catch (Exception exception) {
ctx.status(500).result("An error occurred while granting the item.");
Grasscutter.getLogger().debug("A handbook command error occurred.", exception);
}
}
}

View File

@ -0,0 +1,18 @@
package emu.grasscutter.server.packet.send;
import com.google.protobuf.ByteString;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.WindSeedClientNotifyOuterClass.WindSeedClientNotify;
import emu.grasscutter.net.proto.WindSeedClientNotifyOuterClass.WindSeedClientNotify.AreaNotify;
public final class PacketWindSeedClientNotify extends BasePacket {
public PacketWindSeedClientNotify(byte[] compiledLua) {
super(PacketOpcodes.WindSeedClientNotify);
this.setData(WindSeedClientNotify.newBuilder()
.setAreaNotify(AreaNotify.newBuilder()
.setAreaId(1).setAreaType(1)
.setAreaCode(ByteString.copyFrom(compiledLua))));
}
}

View File

@ -1,16 +1,325 @@
package emu.grasscutter.tools;
import emu.grasscutter.net.proto.GetGachaInfoRspOuterClass.GetGachaInfoRsp;
import emu.grasscutter.net.proto.GetShopRspOuterClass.GetShopRsp;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.Command.TargetRequirement;
import emu.grasscutter.command.CommandMap;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.ResourceLoader;
import emu.grasscutter.game.inventory.ItemType;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.utils.JsonUtils;
import emu.grasscutter.utils.Language;
import lombok.AllArgsConstructor;
public final class Dumpers {
public static void extractBanner(byte[] data) throws Exception {
GetGachaInfoRsp proto = GetGachaInfoRsp.parseFrom(data);
System.out.println(proto);
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public interface Dumpers {
// See `src/handbook/data/README.md` for attributions.
/**
* Fetches the description of a command.
*
* @param locale The locale to use.
* @param command The command to get the description of.
* @return The description of the command.
*/
private static String commandDescription(String locale, Command command) {
try {
// Get the language by the locale.
var language = Language.getLanguage(locale);
if (language == null) throw new IllegalArgumentException("Invalid language.");
return language.get("commands." + command.label() + ".description");
} catch (IllegalArgumentException ignored) {
return command.label();
}
}
public static void extractShop(byte[] data) throws Exception {
GetShopRsp proto = GetShopRsp.parseFrom(data);
System.out.println(proto);
/**
* Encodes the dump into comma separated values.
*
* @param dump The dump to encode.
* @return The encoded dump.
*/
private static String miniEncode(Map<Integer, ?> dump) {
return dump.entrySet().stream()
.map(entry -> entry.getKey() + "," + entry.getValue().toString())
.collect(Collectors.joining("\n"));
}
/**
* Dumps all commands to a JSON file.
*
* @param locale The language to dump the commands in.
*/
static void dumpCommands(String locale) {
// Check that commands are registered.
var commandMap = CommandMap.getInstance();
if (commandMap == null) commandMap = new CommandMap(true);
// Convert all registered commands to an info map.
var dump = new HashMap<String, CommandInfo>();
commandMap.getAnnotationsAsList().forEach(command -> {
var description = Dumpers.commandDescription(locale, command);
var labels = new ArrayList<String>(){{
this.add(command.label());
this.addAll(List.of(command.aliases()));
}};
// Add the command info to the list.
dump.put(command.label(), new CommandInfo(
labels, description, List.of(command.usage()), List.of(
command.permission(), command.permissionTargeted()),
command.targetRequirement()));
});
try {
// Create a file for the dump.
var file = new File("commands.json");
if (file.exists() && !file.delete())
throw new RuntimeException("Failed to delete file.");
if (!file.exists() && !file.createNewFile())
throw new RuntimeException("Failed to create file.");
// Write the dump to the file.
Files.writeString(file.toPath(), JsonUtils.encode(dump));
} catch (IOException ignored) {
throw new RuntimeException("Failed to write to file.");
}
}
/**
* Dumps all avatars to a JSON file.
*
* @param locale The language to dump the avatars in.
*/
static void dumpAvatars(String locale) {
// Reload resources.
ResourceLoader.loadAll();
Language.loadTextMaps();
// Convert all known avatars to an avatar map.
var dump = new HashMap<Integer, AvatarInfo>();
GameData.getAvatarDataMap().forEach((id, avatar) -> {
var langHash = avatar.getNameTextMapHash();
dump.put(id, new AvatarInfo(
langHash == 0 ? avatar.getName() : Language.getTextMapKey(langHash).get(locale),
avatar.getQualityType().equals("QUALITY_PURPLE") ? Quality.EPIC : Quality.LEGENDARY
));
});
try {
// Create a file for the dump.
var file = new File("avatars.csv");
if (file.exists() && !file.delete())
throw new RuntimeException("Failed to delete file.");
if (!file.exists() && !file.createNewFile())
throw new RuntimeException("Failed to create file.");
// Write the dump to the file.
Files.writeString(file.toPath(), Dumpers.miniEncode(dump));
} catch (IOException ignored) {
throw new RuntimeException("Failed to write to file.");
}
}
/**
* Dumps all items to a JSON file.
*
* @param locale The language to dump the items in.
*/
static void dumpItems(String locale) {
// Reload resources.
ResourceLoader.loadAll();
Language.loadTextMaps();
// Convert all known items to an item map.
var originalDump = new ArrayList<ItemInfo>();
GameData.getItemDataMap().forEach((id, item) -> originalDump.add(new ItemInfo(id,
Language.getTextMapKey(item.getNameTextMapHash()).get(locale),
Quality.from(item.getRankLevel()), item.getItemType(),
item.getIcon().length() > 0 ? item.getIcon().substring(3) : ""
)));
// Create a new dump with filtered duplicates.
var names = new ArrayList<String>();
var dump = new HashMap<Integer, ItemInfo>();
originalDump.forEach(item -> {
// Validate the item.
if (item.name.contains("[CHS]")) return;
if (names.contains(item.name)) return;
if (dump.containsKey(item.id)) return;
// Add the item to the dump.
names.add(item.name);
dump.put(item.id, item);
});
try {
// Create a file for the dump.
var file = new File("items.csv");
if (file.exists() && !file.delete())
throw new RuntimeException("Failed to delete file.");
if (!file.exists() && !file.createNewFile())
throw new RuntimeException("Failed to create file.");
// Write the dump to the file.
Files.writeString(file.toPath(), Dumpers.miniEncode(dump));
} catch (IOException ignored) {
throw new RuntimeException("Failed to write to file.");
}
}
/**
* Dumps all scenes to a JSON file.
*/
static void dumpScenes() {
// Reload resources.
ResourceLoader.loadAll();
Language.loadTextMaps();
// Convert all known scenes to a scene map.
var dump = new HashMap<Integer, SceneInfo>();
GameData.getSceneDataMap().forEach((id, scene) ->
dump.put(id, new SceneInfo(scene.getScriptData(), scene.getSceneType())));
try {
// Create a file for the dump.
var file = new File("scenes.csv");
if (file.exists() && !file.delete())
throw new RuntimeException("Failed to delete file.");
if (!file.exists() && !file.createNewFile())
throw new RuntimeException("Failed to create file.");
// Write the dump to the file.
Files.writeString(file.toPath(), Dumpers.miniEncode(dump));
} catch (IOException ignored) {
throw new RuntimeException("Failed to write to file.");
}
}
/**
* Dumps all entities to a JSON file.
*
* @param locale The language to dump the entities in.
*/
static void dumpEntities(String locale) {
// Reload resources.
ResourceLoader.loadAll();
Language.loadTextMaps();
// Convert all known avatars to an avatar map.
var dump = new HashMap<Integer, EntityInfo>();
GameData.getMonsterDataMap().forEach((id, monster) -> {
var langHash = monster.getNameTextMapHash();
dump.put(id, new EntityInfo(
langHash == 0 ? monster.getMonsterName() :
Language.getTextMapKey(langHash).get(locale),
monster.getMonsterName()
));
});
try {
// Create a file for the dump.
var file = new File("entities.csv");
if (file.exists() && !file.delete())
throw new RuntimeException("Failed to delete file.");
if (!file.exists() && !file.createNewFile())
throw new RuntimeException("Failed to create file.");
// Write the dump to the file.
Files.writeString(file.toPath(), Dumpers.miniEncode(dump));
} catch (IOException ignored) {
throw new RuntimeException("Failed to write to file.");
}
}
@AllArgsConstructor
class CommandInfo {
public List<String> name;
public String description;
public List<String> usage;
public List<String> permission;
public TargetRequirement target;
}
@AllArgsConstructor
class AvatarInfo {
public String name;
public Quality quality;
@Override
public String toString() {
return this.name + ","
+ this.quality;
}
}
@AllArgsConstructor
class ItemInfo {
public Integer id;
public String name;
public Quality quality;
public ItemType type;
public String icon;
@Override
public String toString() {
return this.name + ","
+ this.quality + ","
+ this.type + ","
+ this.icon;
}
}
@AllArgsConstructor
class SceneInfo {
public String identifier;
public SceneType type;
@Override
public String toString() {
return this.identifier + ","
+ this.type;
}
}
@AllArgsConstructor
class EntityInfo {
public String name;
public String internal;
@Override
public String toString() {
return this.name + ","
+ this.internal;
}
}
enum Quality {
LEGENDARY, EPIC, RARE, UNCOMMON, COMMON, UNKNOWN;
/**
* Convert a rank level to a quality.
*
* @param rankLevel The rank level to convert.
* @return The quality.
*/
static Quality from(int rankLevel) {
return switch (rankLevel) {
case 0 -> UNKNOWN;
case 1 -> COMMON;
case 2 -> UNCOMMON;
case 3 -> RARE;
case 4 -> EPIC;
default -> LEGENDARY;
};
}
}
}

View File

@ -209,7 +209,7 @@ public final class FileUtils {
return is.readAllBytes();
} catch (Exception exception) {
Grasscutter.getLogger().warn("Failed to read resource: " + resourcePath);
exception.printStackTrace();
Grasscutter.getLogger().debug("Failed to load resource: " + resourcePath, exception);
}
return new byte[0];

View File

@ -10,6 +10,8 @@ import emu.grasscutter.Grasscutter.ServerRunMode;
import emu.grasscutter.net.packet.PacketOpcodesUtils;
import java.util.Map;
import java.util.function.Function;
import emu.grasscutter.tools.Dumpers;
import org.slf4j.LoggerFactory;
/** A parser for start-up arguments. */
@ -47,6 +49,7 @@ public final class StartupArguments {
SERVER.http.encryption.useEncryption = false;
return false;
},
"-dump", StartupArguments::dump,
// Aliases.
"-v", StartupArguments::printVersion,
@ -124,4 +127,38 @@ public final class StartupArguments {
Grasscutter.getLogger().debug("The logger is now running in debug mode.");
return false;
}
/**
* Dumps the specified information.
*
* @param parameter The parameter to dump.
* @return True to exit early.
*/
private static boolean dump(String parameter) {
// Parse the parameter.
if (!parameter.contains(",")) {
Grasscutter.getLogger().error("Dumper usage: -dump=<content>,<language>");
return true;
}
var split = parameter.split(",");
var content = split[0];
var language = split[1];
try {
switch (content.toLowerCase()) {
case "commands" -> Dumpers.dumpCommands(language);
case "avatars" -> Dumpers.dumpAvatars(language);
case "items" -> Dumpers.dumpItems(language);
case "scenes" -> Dumpers.dumpScenes();
case "entities" -> Dumpers.dumpEntities(language);
}
Grasscutter.getLogger().info("Finished dumping.");
} catch (Exception exception) {
Grasscutter.getLogger().error("Unable to complete dump.", exception);
}
return true;
}
}

View File

@ -0,0 +1,32 @@
package emu.grasscutter.utils.objects;
import lombok.Builder;
import lombok.Getter;
/** HTTP request object for handbook controls. */
@SuppressWarnings("FieldMayBeFinal")
public interface HandbookBody {
@Builder
class Response {
private int status;
private String message;
}
@Getter
class GrantAvatar {
private String player; // Parse into online player ID.
private String avatar; // Parse into avatar ID.
private int level = 90; // Range between 1 - 90.
private int constellations = 6; // Range between 0 - 6.
private int talentLevels = 10; // Range between 1 - 15.
}
@Getter
class GiveItem {
private String player; // Parse into online player ID.
private String item; // Parse into item ID.
private int amount = 1; // Range between 1 - Long.MAX_VALUE.
}
}