mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2026-03-28 02:23:31 +01:00
Merge remote-tracking branch 'origin/dev-4.0' into dev-4.0
# Conflicts: # src/main/java/emu/grasscutter/game/player/Player.java # src/main/java/emu/grasscutter/game/player/TeamManager.java # src/main/java/emu/grasscutter/game/world/Scene.java
This commit is contained in:
@@ -10,7 +10,7 @@ import java.util.List;
|
||||
|
||||
@Command(
|
||||
label = "group",
|
||||
aliases = {"g"},
|
||||
aliases = {"gr"},
|
||||
usage = {"(refresh) [<groupId>] [<suiteId>]"},
|
||||
permission = "player.group",
|
||||
permissionTargeted = "player.group.others")
|
||||
|
||||
@@ -12,7 +12,7 @@ import lombok.val;
|
||||
|
||||
@Command(
|
||||
label = "sound",
|
||||
aliases = {"s", "audio"},
|
||||
aliases = {"audio"},
|
||||
usage = {"[<audioname>] [<x><y><z>]"},
|
||||
permission = "player.sound",
|
||||
permissionTargeted = "player.sound.others")
|
||||
|
||||
@@ -4,33 +4,57 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.binout.*;
|
||||
import emu.grasscutter.data.binout.config.*;
|
||||
import emu.grasscutter.data.binout.routes.Route;
|
||||
import emu.grasscutter.data.custom.*;
|
||||
import emu.grasscutter.data.custom.TrialAvatarActivityCustomData;
|
||||
import emu.grasscutter.data.custom.TrialAvatarCustomData;
|
||||
import emu.grasscutter.data.excels.*;
|
||||
import emu.grasscutter.data.excels.achievement.*;
|
||||
import emu.grasscutter.data.excels.activity.*;
|
||||
import emu.grasscutter.data.excels.achievement.AchievementData;
|
||||
import emu.grasscutter.data.excels.achievement.AchievementGoalData;
|
||||
import emu.grasscutter.data.excels.activity.ActivityCondExcelConfigData;
|
||||
import emu.grasscutter.data.excels.activity.ActivityData;
|
||||
import emu.grasscutter.data.excels.activity.ActivityShopData;
|
||||
import emu.grasscutter.data.excels.activity.ActivityWatcherData;
|
||||
import emu.grasscutter.data.excels.avatar.*;
|
||||
import emu.grasscutter.data.excels.codex.*;
|
||||
import emu.grasscutter.data.excels.dungeon.*;
|
||||
import emu.grasscutter.data.excels.giving.*;
|
||||
import emu.grasscutter.data.excels.monster.*;
|
||||
import emu.grasscutter.data.excels.quest.*;
|
||||
import emu.grasscutter.data.excels.reliquary.*;
|
||||
import emu.grasscutter.data.excels.giving.GivingData;
|
||||
import emu.grasscutter.data.excels.giving.GivingGroupData;
|
||||
import emu.grasscutter.data.excels.monster.MonsterCurveData;
|
||||
import emu.grasscutter.data.excels.monster.MonsterData;
|
||||
import emu.grasscutter.data.excels.monster.MonsterDescribeData;
|
||||
import emu.grasscutter.data.excels.monster.MonsterSpecialNameData;
|
||||
import emu.grasscutter.data.excels.quest.QuestData;
|
||||
import emu.grasscutter.data.excels.quest.QuestGlobalVarData;
|
||||
import emu.grasscutter.data.excels.reliquary.ReliquaryAffixData;
|
||||
import emu.grasscutter.data.excels.reliquary.ReliquaryLevelData;
|
||||
import emu.grasscutter.data.excels.reliquary.ReliquaryMainPropData;
|
||||
import emu.grasscutter.data.excels.reliquary.ReliquarySetData;
|
||||
import emu.grasscutter.data.excels.scene.*;
|
||||
import emu.grasscutter.data.excels.tower.*;
|
||||
import emu.grasscutter.data.excels.tower.TowerFloorData;
|
||||
import emu.grasscutter.data.excels.tower.TowerLevelData;
|
||||
import emu.grasscutter.data.excels.tower.TowerScheduleData;
|
||||
import emu.grasscutter.data.excels.trial.*;
|
||||
import emu.grasscutter.data.excels.weapon.*;
|
||||
import emu.grasscutter.data.excels.world.*;
|
||||
import emu.grasscutter.data.excels.weapon.WeaponCurveData;
|
||||
import emu.grasscutter.data.excels.weapon.WeaponLevelData;
|
||||
import emu.grasscutter.data.excels.weapon.WeaponPromoteData;
|
||||
import emu.grasscutter.data.excels.world.WeatherData;
|
||||
import emu.grasscutter.data.excels.world.WorldAreaData;
|
||||
import emu.grasscutter.data.excels.world.WorldLevelData;
|
||||
import emu.grasscutter.data.server.*;
|
||||
import emu.grasscutter.game.dungeons.DungeonDropEntry;
|
||||
import emu.grasscutter.game.quest.*;
|
||||
import emu.grasscutter.game.quest.QuestEncryptionKey;
|
||||
import emu.grasscutter.game.quest.RewindData;
|
||||
import emu.grasscutter.game.quest.TeleportData;
|
||||
import emu.grasscutter.game.quest.enums.QuestCond;
|
||||
import emu.grasscutter.game.world.GroupReplacementData;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import it.unimi.dsi.fastutil.ints.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.val;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.*;
|
||||
|
||||
@SuppressWarnings({"unused", "MismatchedQueryAndUpdateOfCollection"})
|
||||
public final class GameData {
|
||||
@@ -265,6 +289,10 @@ public final class GameData {
|
||||
private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap =
|
||||
new Int2ObjectOpenHashMap<>();
|
||||
|
||||
@Getter
|
||||
private static final Int2ObjectMap<HomeWorldNPCData> homeWorldNPCDataMap =
|
||||
new Int2ObjectOpenHashMap<>();
|
||||
|
||||
@Getter
|
||||
private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap =
|
||||
new Int2ObjectOpenHashMap<>();
|
||||
|
||||
@@ -2,48 +2,49 @@ package emu.grasscutter.data.binout;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import emu.grasscutter.game.world.Position;
|
||||
import java.util.List;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public class HomeworldDefaultSaveData {
|
||||
|
||||
@SerializedName(
|
||||
value = "KFHBFNPDJBE",
|
||||
alternate = {"PKACPHDGGEI", "AKOLOBLHDFK"})
|
||||
value = "homeBlockLists",
|
||||
alternate = {"PKACPHDGGEI", "AKOLOBLHDFK", "KFHBFNPDJBE"})
|
||||
List<HomeBlock> homeBlockLists;
|
||||
|
||||
@SerializedName(
|
||||
value = "IJNPADKGNKE",
|
||||
alternate = {"MINCKHBNING", "MBICDPDEKDM"})
|
||||
value = "bornPos",
|
||||
alternate = {"MINCKHBNING", "MBICDPDEKDM", "IJNPADKGNKE"})
|
||||
Position bornPos;
|
||||
|
||||
@SerializedName(
|
||||
value = "IPIIGEMFLHK",
|
||||
alternate = {"EJJIOJKFKCO"})
|
||||
value = "bornRot",
|
||||
alternate = {"EJJIOJKFKCO", "IPIIGEMFLHK"})
|
||||
Position bornRot;
|
||||
|
||||
@SerializedName(
|
||||
value = "HHOLBNPIHEM",
|
||||
alternate = {"CJAKHCIFHNP"})
|
||||
value = "djinPos",
|
||||
alternate = {"CJAKHCIFHNP", "HHOLBNPIHEM"})
|
||||
Position djinPos;
|
||||
|
||||
@SerializedName(
|
||||
value = "KNHCJKHCOAN",
|
||||
alternate = {"AMDNOHPGKMI"})
|
||||
value = "mainhouse",
|
||||
alternate = {"AMDNOHPGKMI", "KNHCJKHCOAN"})
|
||||
HomeFurniture mainhouse;
|
||||
|
||||
@SerializedName(
|
||||
value = "NIHOJFEKFPG",
|
||||
alternate = {"BHCPEAOPIDC"})
|
||||
value = "doorLists",
|
||||
alternate = {"BHCPEAOPIDC", "NIHOJFEKFPG"})
|
||||
List<HomeFurniture> doorLists;
|
||||
|
||||
@SerializedName(
|
||||
value = "EPGELGEFJFK",
|
||||
alternate = {"AABEPENIFLN"})
|
||||
value = "stairLists",
|
||||
alternate = {"AABEPENIFLN", "EPGELGEFJFK"})
|
||||
List<HomeFurniture> stairLists;
|
||||
|
||||
@Data
|
||||
@@ -51,18 +52,18 @@ public class HomeworldDefaultSaveData {
|
||||
public static class HomeBlock {
|
||||
|
||||
@SerializedName(
|
||||
value = "FGIJCELCGFI",
|
||||
alternate = {"PGDPDIDJEEL", "ANICBLBOBKD"})
|
||||
value = "blockId",
|
||||
alternate = {"PGDPDIDJEEL", "ANICBLBOBKD", "FGIJCELCGFI"})
|
||||
int blockId;
|
||||
|
||||
@SerializedName(
|
||||
value = "BEAPOFELABD",
|
||||
alternate = {"NCIMIKKFLOH"})
|
||||
value = "furnitures",
|
||||
alternate = {"NCIMIKKFLOH", "BEAPOFELABD"})
|
||||
List<HomeFurniture> furnitures;
|
||||
|
||||
@SerializedName(
|
||||
value = "MLIODLGDFHJ",
|
||||
alternate = {"GJGNLIINBGB"})
|
||||
value = "persistentFurnitures",
|
||||
alternate = {"GJGNLIINBGB", "MLIODLGDFHJ"})
|
||||
List<HomeFurniture> persistentFurnitures;
|
||||
}
|
||||
|
||||
@@ -71,15 +72,18 @@ public class HomeworldDefaultSaveData {
|
||||
public static class HomeFurniture {
|
||||
|
||||
@SerializedName(
|
||||
value = "ENHNGKJBJAB",
|
||||
alternate = {"KMAAJJHPNBA", "FFLCGFGGGND"})
|
||||
value = "id",
|
||||
alternate = {"KMAAJJHPNBA", "FFLCGFGGGND", "ENHNGKJBJAB"})
|
||||
int id;
|
||||
|
||||
@SerializedName(
|
||||
value = "NGIEEIOLPPO",
|
||||
alternate = {"JFKAHNCPDME", "BPCGGBKIAMG"})
|
||||
value = "pos",
|
||||
alternate = {"JFKAHNCPDME", "BPCGGBKIAMG", "NGIEEIOLPPO"})
|
||||
Position pos;
|
||||
// @SerializedName(value = "HEOCEHKEBFM", alternate = "LKCKOOGFDBM")
|
||||
|
||||
@SerializedName(
|
||||
value = "rot",
|
||||
alternate = {"LKCKOOGFDBM", "HEOCEHKEBFM"})
|
||||
Position rot;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,10 @@ import lombok.experimental.FieldDefaults;
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@ResourceType(name = {"HomeWorldBgmExcelConfigData.json"})
|
||||
public class HomeWorldBgmData extends GameResource {
|
||||
@SerializedName(value = "homeBgmId", alternate = "MJJENLEBKEF")
|
||||
@SerializedName(value = "homeBgmId", alternate = {"MJJENLEBKEF"})
|
||||
private int homeBgmId;
|
||||
|
||||
@SerializedName(value = "isDefaultUnlock", alternate = {"GBEONILEOBA"})
|
||||
private boolean isDefaultUnlock;
|
||||
private boolean NBIDHGOOCKD;
|
||||
private boolean JJMNJMCCOKP;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.game.inventory.ItemQuality;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ResourceType(name = "HomeWorldNPCExcelConfigData.json")
|
||||
@Getter
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public class HomeWorldNPCData extends GameResource {
|
||||
int furnitureID;
|
||||
int avatarID;
|
||||
@SerializedName(value = "npcId", alternate = {"HDLJMOGHICL"})
|
||||
int npcId;
|
||||
@SerializedName(value = "talkIdList", alternate = {"CKMCLCNIBLD"})
|
||||
List<Integer> talkIdList;
|
||||
@SerializedName(value = "isTalkRandomly", alternate = {"HPJMMEBNMAI"})
|
||||
boolean isTalkRandomly;
|
||||
@SerializedName(value = "npcQuality", alternate = {"BHJOIKFHIBD"})
|
||||
ItemQuality npcQuality;
|
||||
@SerializedName(value = "titleTextMapHash", alternate = {"GNMAIEGCFPO"})
|
||||
long titleTextMapHash;
|
||||
long descTextMapHash;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.avatarID;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.google.gson.annotations.SerializedName;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.data.common.ItemUseData;
|
||||
import emu.grasscutter.game.home.SpecialFurnitureType;
|
||||
import emu.grasscutter.game.inventory.EquipType;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.inventory.MaterialType;
|
||||
@@ -13,10 +14,11 @@ import emu.grasscutter.game.props.ItemUseOp;
|
||||
import emu.grasscutter.game.props.ItemUseTarget;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(
|
||||
name = {
|
||||
@@ -86,6 +88,7 @@ public class ItemData extends GameResource {
|
||||
private int comfort;
|
||||
private List<Integer> furnType;
|
||||
private List<Integer> furnitureGadgetID;
|
||||
private SpecialFurnitureType specialFurnitureType = SpecialFurnitureType.NOT_SPECIAL;
|
||||
|
||||
@SerializedName(
|
||||
value = "roomSceneId",
|
||||
|
||||
@@ -157,6 +157,13 @@ public class AvatarStorage extends BasePlayerManager implements Iterable<Avatar>
|
||||
// Add to avatar storage
|
||||
this.avatars.put(avatar.getAvatarId(), avatar);
|
||||
this.avatarsGuid.put(avatar.getGuid(), avatar);
|
||||
|
||||
// Set main character skill depot data, fixes loading with no element every login
|
||||
if ((avatar.getAvatarId() == 10000007) || (avatar.getAvatarId() == 10000005)) {
|
||||
avatar.setSkillDepot(skillDepot);
|
||||
avatar.setSkillDepotData(skillDepot);
|
||||
avatar.save();
|
||||
}
|
||||
}
|
||||
|
||||
this.setLoaded(true);
|
||||
|
||||
@@ -14,19 +14,24 @@ import org.bson.types.ObjectId;
|
||||
|
||||
@Entity(value = "friendships", useDiscriminator = false)
|
||||
public class Friendship {
|
||||
@Id private ObjectId id;
|
||||
@Id
|
||||
private ObjectId id;
|
||||
|
||||
@Transient private Player owner;
|
||||
@Transient
|
||||
private Player owner;
|
||||
|
||||
@Indexed private int ownerId;
|
||||
@Indexed private int friendId;
|
||||
@Indexed
|
||||
private int ownerId;
|
||||
@Indexed
|
||||
private int friendId;
|
||||
private boolean isFriend;
|
||||
private int askerId;
|
||||
|
||||
private PlayerProfile profile;
|
||||
|
||||
@Deprecated // Morphia use only
|
||||
public Friendship() {}
|
||||
public Friendship() {
|
||||
}
|
||||
|
||||
public Friendship(Player owner, Player friend, Player asker) {
|
||||
this.setOwner(owner);
|
||||
@@ -90,27 +95,28 @@ public class Friendship {
|
||||
}
|
||||
|
||||
public FriendBrief toProto() {
|
||||
FriendBrief proto =
|
||||
FriendBrief.newBuilder()
|
||||
.setUid(getFriendProfile().getUid())
|
||||
.setNickname(getFriendProfile().getName())
|
||||
.setLevel(getFriendProfile().getPlayerLevel())
|
||||
.setProfilePicture(
|
||||
ProfilePicture.newBuilder().setAvatarId(getFriendProfile().getAvatarId()))
|
||||
.setWorldLevel(getFriendProfile().getWorldLevel())
|
||||
.setSignature(getFriendProfile().getSignature())
|
||||
.setOnlineState(
|
||||
getFriendProfile().isOnline()
|
||||
? FriendOnlineState.FRIEND_ONLINE_STATE_ONLINE
|
||||
: FriendOnlineState.FRIEND_ONLINE_STATE_DISCONNECT)
|
||||
.setIsMpModeAvailable(true)
|
||||
.setLastActiveTime(getFriendProfile().getLastActiveTime())
|
||||
.setNameCardId(getFriendProfile().getNameCard())
|
||||
.setParam(getFriendProfile().getDaysSinceLogin())
|
||||
.setIsGameSource(true)
|
||||
.setPlatformType(PlatformTypeOuterClass.PlatformType.PLATFORM_TYPE_PC)
|
||||
.build();
|
||||
var player = this.getFriendProfile().getPlayer(); // get latest player and sync.
|
||||
|
||||
return proto;
|
||||
return FriendBrief.newBuilder()
|
||||
.setUid(getFriendProfile().getUid())
|
||||
.setNickname(getFriendProfile().getName())
|
||||
.setLevel(getFriendProfile().getPlayerLevel())
|
||||
.setProfilePicture(
|
||||
ProfilePicture.newBuilder().setAvatarId(getFriendProfile().getAvatarId()))
|
||||
.setWorldLevel(getFriendProfile().getWorldLevel())
|
||||
.setSignature(getFriendProfile().getSignature())
|
||||
.setOnlineState(
|
||||
player != null && player.isOnline()
|
||||
? FriendOnlineState.FRIEND_ONLINE_STATE_ONLINE
|
||||
: FriendOnlineState.FRIEND_ONLINE_STATE_DISCONNECT)
|
||||
.setIsMpModeAvailable(true)
|
||||
.setLastActiveTime(getFriendProfile().getLastActiveTime())
|
||||
.setNameCardId(getFriendProfile().getNameCard())
|
||||
.setParam(getFriendProfile().getDaysSinceLogin())
|
||||
.setIsGameSource(true)
|
||||
.setPlatformType(PlatformTypeOuterClass.PlatformType.PLATFORM_TYPE_PC)
|
||||
.setIsInDuel(getFriendProfile().isInDuel())
|
||||
.setIsDuelObservable(getFriendProfile().isDuelObservable())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,21 @@ package emu.grasscutter.game.friends;
|
||||
|
||||
import dev.morphia.annotations.AlsoLoad;
|
||||
import dev.morphia.annotations.Entity;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.game.home.GameHome;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.proto.FriendEnterHomeOptionOuterClass;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
public class PlayerProfile {
|
||||
@Transient private Player player;
|
||||
|
||||
@AlsoLoad("id")
|
||||
private int uid;
|
||||
|
||||
@@ -17,12 +24,18 @@ public class PlayerProfile {
|
||||
private int avatarId;
|
||||
private String name;
|
||||
private String signature;
|
||||
private int achievements;
|
||||
|
||||
private int playerLevel;
|
||||
private int worldLevel;
|
||||
private int lastActiveTime;
|
||||
|
||||
private boolean isInDuel = false; // TODO: Implement duels. (TCG)
|
||||
private boolean isDuelObservable = false; // TODO: Implement duels. (TCG)
|
||||
|
||||
@Getter
|
||||
private int enterHomeOption;
|
||||
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public PlayerProfile() {}
|
||||
|
||||
@@ -31,50 +44,13 @@ public class PlayerProfile {
|
||||
this.syncWithCharacter(player);
|
||||
}
|
||||
|
||||
public int getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Player getPlayer() {
|
||||
var player = Grasscutter.getGameServer().getPlayerByUid(this.getUid(), true);
|
||||
this.syncWithCharacter(player);
|
||||
return player;
|
||||
}
|
||||
|
||||
public synchronized void setPlayer(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getNameCard() {
|
||||
return nameCard;
|
||||
}
|
||||
|
||||
public int getAvatarId() {
|
||||
return avatarId;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public int getAchievements() {
|
||||
return achievements;
|
||||
}
|
||||
|
||||
public int getPlayerLevel() {
|
||||
return playerLevel;
|
||||
}
|
||||
|
||||
public int getWorldLevel() {
|
||||
return worldLevel;
|
||||
}
|
||||
|
||||
public int getLastActiveTime() {
|
||||
return lastActiveTime;
|
||||
}
|
||||
|
||||
public void updateLastActiveTime() {
|
||||
this.lastActiveTime = Utils.getCurrentSeconds();
|
||||
}
|
||||
@@ -83,10 +59,6 @@ public class PlayerProfile {
|
||||
return (int) Math.floor((Utils.getCurrentSeconds() - getLastActiveTime()) / 86400.0);
|
||||
}
|
||||
|
||||
public boolean isOnline() {
|
||||
return this.getPlayer() != null;
|
||||
}
|
||||
|
||||
public void syncWithCharacter(Player player) {
|
||||
if (player == null) {
|
||||
return;
|
||||
@@ -99,7 +71,7 @@ public class PlayerProfile {
|
||||
this.nameCard = player.getNameCardId();
|
||||
this.playerLevel = player.getLevel();
|
||||
this.worldLevel = player.getWorldLevel();
|
||||
// this.achievements = 0;
|
||||
this.enterHomeOption = player.tryGetHome().map(GameHome::getEnterHomeOption).orElse(FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.FRIEND_ENTER_HOME_OPTION_REFUSE_VALUE);
|
||||
this.updateLastActiveTime();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package emu.grasscutter.game.home;
|
||||
|
||||
import emu.grasscutter.game.CoopRequest;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
public class EnterHomeRequest extends CoopRequest {
|
||||
public EnterHomeRequest(Player requester) {
|
||||
super(requester);
|
||||
}
|
||||
}
|
||||
@@ -4,31 +4,40 @@ import dev.morphia.annotations.*;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.HomeWorldLevelData;
|
||||
import emu.grasscutter.data.excels.scene.SceneData;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Entity(value = "homes", useDiscriminator = false)
|
||||
@Data
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Builder(builderMethodName = "of")
|
||||
public class GameHome {
|
||||
@Id String id;
|
||||
public static final Set<Integer> HOME_SCENE_IDS = GameData.getSceneDataMap().values().stream()
|
||||
.filter(sceneData -> sceneData.getSceneType() == SceneType.SCENE_HOME_WORLD || sceneData.getSceneType() == SceneType.SCENE_HOME_ROOM)
|
||||
.map(SceneData::getId).collect(Collectors.toUnmodifiableSet());
|
||||
|
||||
@Id
|
||||
String id;
|
||||
|
||||
@Indexed(options = @IndexOptions(unique = true))
|
||||
long ownerUid;
|
||||
|
||||
@Transient Player player;
|
||||
@Transient
|
||||
Player player;
|
||||
|
||||
int level;
|
||||
int exp;
|
||||
@@ -49,13 +58,17 @@ public class GameHome {
|
||||
return home;
|
||||
}
|
||||
|
||||
public static boolean doesHomeExist(int uid) {
|
||||
return DatabaseHelper.getHomeByUid(uid) != null;
|
||||
}
|
||||
|
||||
public static GameHome create(Integer uid) {
|
||||
return GameHome.of()
|
||||
.ownerUid(uid)
|
||||
.level(1)
|
||||
.sceneMap(new ConcurrentHashMap<>())
|
||||
.unlockedHomeBgmList(new HashSet<>())
|
||||
.build();
|
||||
.ownerUid(uid)
|
||||
.level(1)
|
||||
.sceneMap(new ConcurrentHashMap<>())
|
||||
.unlockedHomeBgmList(new HashSet<>())
|
||||
.build();
|
||||
}
|
||||
|
||||
public void save() {
|
||||
@@ -64,19 +77,19 @@ public class GameHome {
|
||||
|
||||
public HomeSceneItem getHomeSceneItem(int sceneId) {
|
||||
return sceneMap.computeIfAbsent(
|
||||
sceneId,
|
||||
e -> {
|
||||
var defaultItem = GameData.getHomeworldDefaultSaveData().get(sceneId);
|
||||
if (defaultItem != null) {
|
||||
Grasscutter.getLogger()
|
||||
.info("Set player {} home {} to initial setting", ownerUid, sceneId);
|
||||
return HomeSceneItem.parseFrom(defaultItem, sceneId);
|
||||
} else {
|
||||
// Realm res missing bricks account, use default realm data to allow main house
|
||||
defaultItem = GameData.getHomeworldDefaultSaveData().get(2001);
|
||||
return HomeSceneItem.parseFrom(defaultItem, sceneId);
|
||||
}
|
||||
});
|
||||
sceneId,
|
||||
e -> {
|
||||
var defaultItem = GameData.getHomeworldDefaultSaveData().get(sceneId);
|
||||
if (defaultItem != null) {
|
||||
Grasscutter.getLogger()
|
||||
.info("Set player {} home {} to initial setting", ownerUid, sceneId);
|
||||
return HomeSceneItem.parseFrom(defaultItem, sceneId);
|
||||
} else {
|
||||
// Realm res missing bricks account, use default realm data to allow main house
|
||||
defaultItem = GameData.getHomeworldDefaultSaveData().get(2001);
|
||||
return HomeSceneItem.parseFrom(defaultItem, sceneId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onOwnerLogin(Player player) {
|
||||
@@ -130,9 +143,9 @@ public class GameHome {
|
||||
|
||||
private Set<Integer> getDefaultUnlockedHomeBgmIds() {
|
||||
return GameData.getHomeWorldBgmDataMap().int2ObjectEntrySet().stream()
|
||||
.filter(e -> e.getValue().isDefaultUnlock())
|
||||
.map(Int2ObjectMap.Entry::getIntKey)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
.filter(e -> e.getValue().isDefaultUnlock())
|
||||
.map(Int2ObjectMap.Entry::getIntKey)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
// Same as Player.java addExpDirectly
|
||||
@@ -171,7 +184,7 @@ public class GameHome {
|
||||
|
||||
// Ensure next update is at top of the hour
|
||||
nextUpdateTime =
|
||||
(int) ZonedDateTime.now().plusHours(1).truncatedTo(ChronoUnit.HOURS).toEpochSecond();
|
||||
(int) ZonedDateTime.now().plusHours(1).truncatedTo(ChronoUnit.HOURS).toEpochSecond();
|
||||
|
||||
// Get resources
|
||||
var hourlyResources = getComfortResources(player);
|
||||
@@ -194,42 +207,42 @@ public class GameHome {
|
||||
|
||||
// Outdoors avatars
|
||||
sceneMap
|
||||
.get(player.getCurrentRealmId() + 2000)
|
||||
.getBlockItems()
|
||||
.forEach(
|
||||
(i, e) -> {
|
||||
e.getDeployNPCList()
|
||||
.forEach(
|
||||
id -> {
|
||||
invitedAvatars.add(id.getAvatarId());
|
||||
});
|
||||
});
|
||||
.get(player.getCurrentRealmId() + 2000)
|
||||
.getBlockItems()
|
||||
.forEach(
|
||||
(i, e) -> {
|
||||
e.getDeployNPCList()
|
||||
.forEach(
|
||||
id -> {
|
||||
invitedAvatars.add(id.getAvatarId());
|
||||
});
|
||||
});
|
||||
|
||||
// Check as realm 5 inside is not in defaults and will be null
|
||||
if (Objects.nonNull(sceneMap.get(player.getCurrentRealmId() + 2200))) {
|
||||
// Indoors avatars
|
||||
sceneMap
|
||||
.get(player.getCurrentRealmId() + 2200)
|
||||
.getBlockItems()
|
||||
.forEach(
|
||||
(i, e) -> {
|
||||
e.getDeployNPCList()
|
||||
.forEach(
|
||||
id -> {
|
||||
invitedAvatars.add(id.getAvatarId());
|
||||
});
|
||||
});
|
||||
.get(player.getCurrentRealmId() + 2200)
|
||||
.getBlockItems()
|
||||
.forEach(
|
||||
(i, e) -> {
|
||||
e.getDeployNPCList()
|
||||
.forEach(
|
||||
id -> {
|
||||
invitedAvatars.add(id.getAvatarId());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Add exp to all avatars
|
||||
invitedAvatars.forEach(
|
||||
id -> {
|
||||
var avatar = player.getAvatars().getAvatarById(id);
|
||||
player
|
||||
.getServer()
|
||||
.getInventorySystem()
|
||||
.upgradeAvatarFetterLevel(player, avatar, storedFetterExp);
|
||||
});
|
||||
id -> {
|
||||
var avatar = player.getAvatars().getAvatarById(id);
|
||||
player
|
||||
.getServer()
|
||||
.getInventorySystem()
|
||||
.upgradeAvatarFetterLevel(player, avatar, storedFetterExp);
|
||||
});
|
||||
|
||||
storedFetterExp = 0;
|
||||
save();
|
||||
@@ -253,7 +266,7 @@ public class GameHome {
|
||||
storeResources(player, 0, 0);
|
||||
lastUpdatedTime = clientTime;
|
||||
nextUpdateTime =
|
||||
(int) ZonedDateTime.now().plusHours(1).truncatedTo(ChronoUnit.HOURS).toEpochSecond();
|
||||
(int) ZonedDateTime.now().plusHours(1).truncatedTo(ChronoUnit.HOURS).toEpochSecond();
|
||||
save();
|
||||
|
||||
// Send packet
|
||||
|
||||
@@ -4,12 +4,15 @@ import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Id;
|
||||
import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
|
||||
import emu.grasscutter.net.proto.HomeBlockArrangementInfoOuterClass.HomeBlockArrangementInfo;
|
||||
import java.util.List;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@Builder(builderMethodName = "of")
|
||||
@@ -77,6 +80,8 @@ public class HomeBlockItem {
|
||||
.setIsUnlocked(unlocked)
|
||||
.setComfortValue(calComfort());
|
||||
|
||||
this.reassignIfNull();
|
||||
|
||||
this.deployFurnitureList.forEach(f -> proto.addDeployFurniureList(f.toProto()));
|
||||
this.persistentFurnitureList.forEach(f -> proto.addPersistentFurnitureList(f.toProto()));
|
||||
this.deployAnimalList.forEach(f -> proto.addDeployAnimalList(f.toProto()));
|
||||
@@ -84,4 +89,26 @@ public class HomeBlockItem {
|
||||
|
||||
return proto.build();
|
||||
}
|
||||
|
||||
// TODO add more types (farm field and suite)
|
||||
public List<? extends HomeMarkPointProtoFactory> getMarkPointProtoFactories() {
|
||||
this.reassignIfNull();
|
||||
|
||||
return Stream.of(this.deployFurnitureList, this.persistentFurnitureList, this.deployNPCList).flatMap(Collection::stream).toList();
|
||||
}
|
||||
|
||||
public void reassignIfNull() {
|
||||
if (this.deployFurnitureList == null) {
|
||||
this.deployFurnitureList = List.of();
|
||||
}
|
||||
if (this.persistentFurnitureList == null) {
|
||||
this.persistentFurnitureList = List.of();
|
||||
}
|
||||
if (this.deployAnimalList == null) {
|
||||
this.deployAnimalList = List.of();
|
||||
}
|
||||
if (this.deployNPCList == null) {
|
||||
this.deployNPCList = List.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,24 @@ import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Builder(builderMethodName = "of")
|
||||
public class HomeFurnitureItem {
|
||||
public class HomeFurnitureItem implements HomeMarkPointProtoFactory {
|
||||
public static final int PAIMON_FURNITURE_ID = 368134;
|
||||
public static final int TELEPORT_FURNITURE_ID = 373501;
|
||||
public static final Set<Integer> APARTMENT_FURNITURE_ID_SET = GameData.getItemDataMap().values()
|
||||
.stream()
|
||||
.filter(itemData -> itemData.getSpecialFurnitureType() == SpecialFurnitureType.Apartment)
|
||||
.map(ItemData::getId)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
|
||||
int furnitureId;
|
||||
int guid;
|
||||
int parentFurnitureIndex;
|
||||
@@ -41,7 +53,7 @@ public class HomeFurnitureItem {
|
||||
.furnitureId(homeFurniture.getId())
|
||||
.parentFurnitureIndex(1)
|
||||
.spawnPos(homeFurniture.getPos() == null ? new Position() : homeFurniture.getPos())
|
||||
.spawnRot(homeFurniture.getRot() == null ? new Position() : homeFurniture.getRot())
|
||||
.spawnRot(new Position())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -56,17 +68,6 @@ public class HomeFurnitureItem {
|
||||
.build();
|
||||
}
|
||||
|
||||
public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto(
|
||||
int type) {
|
||||
return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
|
||||
.setFurnitureId(furnitureId)
|
||||
.setGuid(guid)
|
||||
.setFurnitureType(type)
|
||||
.setPos(spawnPos.toProto())
|
||||
// TODO NPC and farm
|
||||
.build();
|
||||
}
|
||||
|
||||
public ItemData getAsItem() {
|
||||
return GameData.getItemDataMap().get(this.furnitureId);
|
||||
}
|
||||
@@ -79,4 +80,29 @@ public class HomeFurnitureItem {
|
||||
}
|
||||
return item.getComfort();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto() {
|
||||
var type = this.adjustByFurnitureId();
|
||||
if (type == SpecialFurnitureType.NOT_SPECIAL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
|
||||
.setFurnitureId(this.furnitureId)
|
||||
.setFurnitureType(type.getValue())
|
||||
.setPos(this.spawnPos.toProto())
|
||||
.setGuid(this.guid)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpecialFurnitureType adjustByFurnitureId() {
|
||||
return switch (this.furnitureId) {
|
||||
case PAIMON_FURNITURE_ID -> SpecialFurnitureType.Paimon;
|
||||
case TELEPORT_FURNITURE_ID -> SpecialFurnitureType.TeleportPoint;
|
||||
default -> APARTMENT_FURNITURE_ID_SET.contains(this.furnitureId) ? SpecialFurnitureType.Apartment : SpecialFurnitureType.NOT_SPECIAL;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package emu.grasscutter.game.home;
|
||||
|
||||
import emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface HomeMarkPointProtoFactory {
|
||||
@Nullable
|
||||
HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto();
|
||||
|
||||
default SpecialFurnitureType adjustByFurnitureId() {
|
||||
return this.getType();
|
||||
}
|
||||
|
||||
default SpecialFurnitureType getType() {
|
||||
return SpecialFurnitureType.NOT_SPECIAL;
|
||||
}
|
||||
|
||||
default boolean isProtoConvertible() {
|
||||
return this.adjustByFurnitureId() != SpecialFurnitureType.NOT_SPECIAL;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,23 @@
|
||||
package emu.grasscutter.game.home;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.game.world.Position;
|
||||
import emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass;
|
||||
import emu.grasscutter.net.proto.HomeMarkPointNPCDataOuterClass;
|
||||
import emu.grasscutter.net.proto.HomeNpcDataOuterClass;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Builder(builderMethodName = "of")
|
||||
public class HomeNPCItem {
|
||||
public class HomeNPCItem implements HomeMarkPointProtoFactory {
|
||||
transient int furnitureId;
|
||||
int avatarId;
|
||||
Position spawnPos;
|
||||
Position spawnRot;
|
||||
@@ -20,19 +25,52 @@ public class HomeNPCItem {
|
||||
|
||||
public static HomeNPCItem parseFrom(HomeNpcDataOuterClass.HomeNpcData homeNpcData) {
|
||||
return HomeNPCItem.of()
|
||||
.avatarId(homeNpcData.getAvatarId())
|
||||
.spawnPos(new Position(homeNpcData.getSpawnPos()))
|
||||
.spawnRot(new Position(homeNpcData.getSpawnRot()))
|
||||
.costumeId(homeNpcData.getCostumeId())
|
||||
.build();
|
||||
.avatarId(homeNpcData.getAvatarId())
|
||||
.spawnPos(new Position(homeNpcData.getSpawnPos()))
|
||||
.spawnRot(new Position(homeNpcData.getSpawnRot()))
|
||||
.costumeId(homeNpcData.getCostumeId())
|
||||
.build();
|
||||
}
|
||||
|
||||
public HomeNpcDataOuterClass.HomeNpcData toProto() {
|
||||
return HomeNpcDataOuterClass.HomeNpcData.newBuilder()
|
||||
.setAvatarId(avatarId)
|
||||
.setSpawnPos(spawnPos.toProto())
|
||||
.setSpawnRot(spawnRot.toProto())
|
||||
.setCostumeId(costumeId)
|
||||
.build();
|
||||
.setAvatarId(avatarId)
|
||||
.setSpawnPos(spawnPos.toProto())
|
||||
.setSpawnRot(spawnRot.toProto())
|
||||
.setCostumeId(costumeId)
|
||||
.build();
|
||||
}
|
||||
|
||||
public int getFurnitureId() {
|
||||
if (this.furnitureId == 0) {
|
||||
var data = GameData.getHomeWorldNPCDataMap().get(this.avatarId);
|
||||
this.furnitureId = data == null ? -1 : data.getFurnitureID();
|
||||
}
|
||||
|
||||
return this.furnitureId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto() {
|
||||
return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
|
||||
.setFurnitureId(this.getFurnitureId())
|
||||
.setFurnitureType(this.getType().getValue())
|
||||
.setPos(this.spawnPos.toProto())
|
||||
.setNpcData(HomeMarkPointNPCDataOuterClass.HomeMarkPointNPCData.newBuilder()
|
||||
.setAvatarId(this.avatarId)
|
||||
.setCostumeId(this.costumeId)
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpecialFurnitureType getType() {
|
||||
return SpecialFurnitureType.NPC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProtoConvertible() {
|
||||
return this.getFurnitureId() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
|
||||
import emu.grasscutter.game.world.Position;
|
||||
import emu.grasscutter.net.proto.HomeSceneArrangementInfoOuterClass.HomeSceneArrangementInfo;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@Builder(builderMethodName = "of")
|
||||
@@ -64,12 +65,16 @@ public class HomeSceneItem {
|
||||
}
|
||||
|
||||
public int getRoomSceneId() {
|
||||
if (mainHouse == null || mainHouse.getAsItem() == null) {
|
||||
if (this.isRoom()) {
|
||||
return 0;
|
||||
}
|
||||
return mainHouse.getAsItem().getRoomSceneId();
|
||||
}
|
||||
|
||||
public boolean isRoom() {
|
||||
return mainHouse == null || mainHouse.getAsItem() == null;
|
||||
}
|
||||
|
||||
public int calComfort() {
|
||||
return this.blockItems.values().stream().mapToInt(HomeBlockItem::calComfort).sum();
|
||||
}
|
||||
|
||||
162
src/main/java/emu/grasscutter/game/home/HomeWorld.java
Normal file
162
src/main/java/emu/grasscutter/game/home/HomeWorld.java
Normal file
@@ -0,0 +1,162 @@
|
||||
package emu.grasscutter.game.home;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityTeam;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.ChatInfoOuterClass;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerChatNotify;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class HomeWorld extends World {
|
||||
@Getter
|
||||
private final GameHome home;
|
||||
|
||||
public HomeWorld(GameServer server, Player owner) {
|
||||
super(server, owner);
|
||||
|
||||
this.home = owner.isOnline() ? owner.getHome() : GameHome.getByUid(owner.getUid());
|
||||
server.registerHomeWorld(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addPlayer(Player player) {
|
||||
// Check if player already in
|
||||
if (this.getPlayers().contains(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove player from prev world
|
||||
if (player.getWorld() != null) {
|
||||
player.getWorld().removePlayer(player);
|
||||
}
|
||||
|
||||
// Register
|
||||
player.setWorld(this);
|
||||
this.getPlayers().add(player);
|
||||
|
||||
// Set player variables
|
||||
if (this.getHost().equals(player)) {
|
||||
player.setPeerId(1);
|
||||
this.getGuests().forEach(player1 -> player1.setPeerId(player1.getPeerId() + 1));
|
||||
} else {
|
||||
player.setPeerId(this.getNextPeerId());
|
||||
}
|
||||
|
||||
player.getTeamManager().setEntity(new EntityTeam(player));
|
||||
|
||||
// Copy main team to multiplayer team
|
||||
if (this.isMultiplayer()) {
|
||||
player
|
||||
.getTeamManager()
|
||||
.getMpTeam()
|
||||
.copyFrom(
|
||||
player.getTeamManager().getCurrentSinglePlayerTeamInfo(),
|
||||
player.getTeamManager().getMaxTeamSize());
|
||||
player.getTeamManager().setCurrentCharacterIndex(0);
|
||||
|
||||
if (!player.equals(this.getHost())) {
|
||||
this.broadcastPacket(
|
||||
new PacketPlayerChatNotify(
|
||||
player,
|
||||
0,
|
||||
ChatInfoOuterClass.ChatInfo.SystemHint.newBuilder()
|
||||
.setType(ChatInfoOuterClass.ChatInfo.SystemHintType.SYSTEM_HINT_TYPE_CHAT_ENTER_WORLD.getNumber())
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
// Add to scene
|
||||
var scene = this.getSceneById(player.getSceneId());
|
||||
scene.addPlayer(player);
|
||||
|
||||
// Info packet for other players
|
||||
if (this.getPlayers().size() > 1) {
|
||||
this.updatePlayerInfos(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void removePlayer(Player player) {
|
||||
// Remove team entities
|
||||
this.broadcastPacket(
|
||||
new PacketDelTeamEntityNotify(
|
||||
player.getSceneId(),
|
||||
this.getPlayers().stream()
|
||||
.map(
|
||||
p ->
|
||||
p.getTeamManager().getEntity() == null
|
||||
? 0
|
||||
: p.getTeamManager().getEntity().getId())
|
||||
.toList()));
|
||||
|
||||
// Deregister
|
||||
this.getPlayers().remove(player);
|
||||
player.setWorld(null);
|
||||
|
||||
// Remove from scene
|
||||
Scene scene = this.getSceneById(player.getSceneId());
|
||||
scene.removePlayer(player);
|
||||
|
||||
// Info packet for other players
|
||||
if (this.getPlayers().size() > 0) {
|
||||
this.updatePlayerInfos(player);
|
||||
}
|
||||
|
||||
this.broadcastPacket(
|
||||
new PacketPlayerChatNotify(
|
||||
player,
|
||||
0,
|
||||
ChatInfoOuterClass.ChatInfo.SystemHint.newBuilder()
|
||||
.setType(ChatInfoOuterClass.ChatInfo.SystemHintType.SYSTEM_HINT_TYPE_CHAT_LEAVE_WORLD.getNumber())
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextPeerId() {
|
||||
return this.getPlayers().size() + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setHost(Player host) {
|
||||
super.setHost(host);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isMultiplayer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isPaused() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isTimeLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getOwnerUid() {
|
||||
return this.getHost().getUid();
|
||||
}
|
||||
|
||||
public List<Player> getGuests() {
|
||||
return this.getPlayers().stream().filter(player -> !player.equals(this.getHost())).toList();
|
||||
}
|
||||
|
||||
public boolean isInHome(Player player) {
|
||||
return this.getPlayers().contains(player);
|
||||
}
|
||||
|
||||
public void sendPacketToHostIfOnline(BasePacket basePacket) {
|
||||
if (this.getHost().isOnline()) {
|
||||
this.getHost().sendPacket(basePacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
187
src/main/java/emu/grasscutter/game/home/HomeWorldMPSystem.java
Normal file
187
src/main/java/emu/grasscutter/game/home/HomeWorldMPSystem.java
Normal file
@@ -0,0 +1,187 @@
|
||||
package emu.grasscutter.game.home;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.EnterReason;
|
||||
import emu.grasscutter.game.world.Position;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.game.world.data.TeleportProperties;
|
||||
import emu.grasscutter.net.proto.EnterTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.OtherPlayerEnterHomeNotifyOuterClass;
|
||||
import emu.grasscutter.net.proto.PlayerApplyEnterHomeResultNotifyOuterClass;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||
import emu.grasscutter.server.event.player.PlayerEnterHomeEvent;
|
||||
import emu.grasscutter.server.event.player.PlayerLeaveHomeEvent;
|
||||
import emu.grasscutter.server.event.player.PlayerTeleportEvent;
|
||||
import emu.grasscutter.server.game.BaseGameSystem;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
|
||||
public class HomeWorldMPSystem extends BaseGameSystem {
|
||||
public HomeWorldMPSystem(GameServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
public void sendEnterHomeRequest(Player requester, int ownerUid) {
|
||||
var owner = getServer().getPlayerByUid(ownerUid);
|
||||
if (owner == null) {
|
||||
requester.sendPacket(new PacketPlayerApplyEnterHomeResultNotify(ownerUid, "", false, PlayerApplyEnterHomeResultNotifyOuterClass.PlayerApplyEnterHomeResultNotify.Reason.OPEN_STATE_NOT_OPEN));
|
||||
requester.sendPacket(new PacketTryEnterHomeRsp());
|
||||
return;
|
||||
}
|
||||
|
||||
if (owner.getRealmList() == null) {
|
||||
requester.sendPacket(new PacketPlayerApplyEnterHomeResultNotify(ownerUid, "", false, PlayerApplyEnterHomeResultNotifyOuterClass.PlayerApplyEnterHomeResultNotify.Reason.OPEN_STATE_NOT_OPEN));
|
||||
requester.sendPacket(new PacketTryEnterHomeRsp());
|
||||
return;
|
||||
}
|
||||
|
||||
var request = owner.getEnterHomeRequests().get(requester.getUid());
|
||||
|
||||
if (request != null && !request.isExpired()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (owner.isInEditMode()) {
|
||||
requester.sendPacket(new PacketPlayerApplyEnterHomeResultNotify(ownerUid, owner.getNickname(), false, PlayerApplyEnterHomeResultNotifyOuterClass.PlayerApplyEnterHomeResultNotify.Reason.HOST_IN_EDIT_MODE));
|
||||
requester.sendPacket(new PacketTryEnterHomeRsp());
|
||||
return;
|
||||
}
|
||||
|
||||
request = new EnterHomeRequest(requester);
|
||||
owner.getEnterHomeRequests().put(requester.getUid(), request);
|
||||
|
||||
owner.sendPacket(new PacketPlayerApplyEnterHomeNotify(requester));
|
||||
}
|
||||
|
||||
public void acceptEnterHomeRequest(Player owner, int requesterUid, boolean isAgreed) {
|
||||
var request = owner.getEnterHomeRequests().get(requesterUid);
|
||||
if (request == null || request.isExpired()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var requester = request.getRequester();
|
||||
owner.getEnterHomeRequests().remove(requesterUid);
|
||||
|
||||
if (requester.getWorld().isMultiplayer()) {
|
||||
requester.sendPacket(new PacketPlayerApplyEnterHomeResultNotify(owner.getUid(), owner.getNickname(), false, PlayerApplyEnterHomeResultNotifyOuterClass.PlayerApplyEnterHomeResultNotify.Reason.SYSTEM_JUDGE));
|
||||
requester.sendPacket(new PacketTryEnterHomeRsp());
|
||||
return;
|
||||
}
|
||||
|
||||
requester.sendPacket(new PacketPlayerApplyEnterHomeResultNotify(owner.getUid(), owner.getNickname(), isAgreed, PlayerApplyEnterHomeResultNotifyOuterClass.PlayerApplyEnterHomeResultNotify.Reason.PLAYER_JUDGE));
|
||||
|
||||
if (!isAgreed) {
|
||||
requester.sendPacket(new PacketTryEnterHomeRsp());
|
||||
return;
|
||||
}
|
||||
|
||||
this.enterHome(requester, owner);
|
||||
}
|
||||
|
||||
public void enterHome(Player requester, Player owner) {
|
||||
if (requester.getWorld().isMultiplayer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (owner.getRealmList() == null) {
|
||||
// should never happen
|
||||
requester.sendPacket(new PacketTryEnterHomeRsp(RetcodeOuterClass.Retcode.RET_HOME_NOT_FOUND_IN_MEM_VALUE, owner.getUid()));
|
||||
return;
|
||||
}
|
||||
|
||||
var world = this.server.getHomeWorldOrCreate(owner);
|
||||
var targetHome = world.getHome();
|
||||
|
||||
var event = new PlayerEnterHomeEvent(requester, owner, targetHome);
|
||||
event.call();
|
||||
if (event.isCanceled()) {
|
||||
requester.sendPacket(new PacketTryEnterHomeRsp(RetcodeOuterClass.Retcode.RET_HOME_OWNER_REFUSE_TO_ENTER_HOME_VALUE, owner.getUid()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (owner.isInEditMode()) {
|
||||
requester.sendPacket(new PacketTryEnterHomeRsp(RetcodeOuterClass.Retcode.RET_HOME_CANT_ENTER_BY_IN_EDIT_MODE_VALUE, owner.getUid()));
|
||||
return;
|
||||
}
|
||||
|
||||
int realmId = 2000 + owner.getCurrentRealmId();
|
||||
targetHome.getHomeSceneItem(realmId);
|
||||
targetHome.save();
|
||||
var pos = world.getSceneById(realmId).getScriptManager().getConfig().born_pos;
|
||||
|
||||
requester.getPrevPosForHome().set(requester.getPosition());
|
||||
requester.setCurHomeWorld(world);
|
||||
requester.setPrevScene(requester.getSceneId());
|
||||
world.addPlayer(requester, realmId);
|
||||
requester.setSceneId(realmId);
|
||||
requester.getPosition().set(pos);
|
||||
|
||||
requester.sendPacket(new PacketPlayerEnterSceneNotify(requester, owner.getUid(), TeleportProperties.builder().sceneId(realmId).enterReason(EnterReason.EnterHome).teleportTo(pos).teleportType(PlayerTeleportEvent.TeleportType.INTERNAL).build(), !requester.equals(owner)));
|
||||
requester.sendPacket(new PacketTryEnterHomeRsp(owner.getUid()));
|
||||
|
||||
requester.setHasSentInitPacketInHome(false);
|
||||
world.getPlayers().stream()
|
||||
.filter(player -> !player.equals(requester))
|
||||
.forEach(player -> player.sendPacket(new PacketPlayerPreEnterMpNotify(requester)));
|
||||
}
|
||||
|
||||
public boolean leaveCoop(Player player, int prevScene) {
|
||||
return this.leaveCoop(player, prevScene, player.getPrevPosForHome());
|
||||
}
|
||||
|
||||
public boolean leaveCoop(Player player, int prevScene, Position pos) {
|
||||
// Make sure everyone's scene is loaded
|
||||
for (var p : player.getWorld().getPlayers()) {
|
||||
if (p.getSceneLoadState() != Player.SceneLoadState.LOADED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Event
|
||||
var event = new PlayerLeaveHomeEvent(player, player.getCurHomeWorld().getHost(), player.getCurHomeWorld().getHome(), PlayerLeaveHomeEvent.Reason.PLAYER_LEAVE);
|
||||
event.call();
|
||||
|
||||
player.getPosition().set(pos);
|
||||
var world = new World(player);
|
||||
world.addPlayer(player, prevScene);
|
||||
player.getCurHomeWorld().sendPacketToHostIfOnline(new PacketOtherPlayerEnterOrLeaveHomeNotify(player, OtherPlayerEnterHomeNotifyOuterClass.OtherPlayerEnterHomeNotify.Reason.LEAVE));
|
||||
player.setCurHomeWorld(this.server.getHomeWorldOrCreate(player));
|
||||
|
||||
player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterTypeOuterClass.EnterType.ENTER_TYPE_BACK, EnterReason.TeamBack, prevScene, pos));
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean kickPlayerFromHome(Player owner, int targetUid) {
|
||||
// Make sure player's world is multiplayer and that player is owner
|
||||
if (!owner.getCurHomeWorld().getHost().equals(owner)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get victim and sanity checks
|
||||
var victim = owner.getServer().getPlayerByUid(targetUid);
|
||||
if (victim == null || owner.equals(victim)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure victim's scene has loaded
|
||||
if (victim.getSceneLoadState() != Player.SceneLoadState.LOADED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Event
|
||||
var event = new PlayerLeaveHomeEvent(victim, owner, victim.getCurHomeWorld().getHome(), PlayerLeaveHomeEvent.Reason.KICKED);
|
||||
event.call();
|
||||
|
||||
// Kick
|
||||
victim.getPosition().set(victim.getPrevPosForHome());
|
||||
var world = new World(victim);
|
||||
world.addPlayer(victim, 3);
|
||||
victim.getCurHomeWorld().sendPacketToHostIfOnline(new PacketOtherPlayerEnterOrLeaveHomeNotify(victim, OtherPlayerEnterHomeNotifyOuterClass.OtherPlayerEnterHomeNotify.Reason.LEAVE));
|
||||
victim.setCurHomeWorld(this.server.getHomeWorldOrCreate(victim));
|
||||
|
||||
victim.sendPacket(new PacketPlayerEnterSceneNotify(victim, EnterTypeOuterClass.EnterType.ENTER_TYPE_BACK, EnterReason.TeamKick, victim.getScene().getId(), victim.getPrevPosForHome()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package emu.grasscutter.game.home;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum SpecialFurnitureType {
|
||||
NOT_SPECIAL(-1),
|
||||
FarmField(2),
|
||||
TeleportPoint(3),
|
||||
NPC(5),
|
||||
Apartment(6),
|
||||
FurnitureSuite(7),
|
||||
Paimon(8);
|
||||
|
||||
private final int value;
|
||||
|
||||
SpecialFurnitureType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -17,15 +17,26 @@ import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.game.expedition.ExpeditionInfo;
|
||||
import emu.grasscutter.game.friends.*;
|
||||
import emu.grasscutter.game.gacha.PlayerGachaInfo;
|
||||
import emu.grasscutter.game.home.EnterHomeRequest;
|
||||
import emu.grasscutter.game.home.GameHome;
|
||||
import emu.grasscutter.game.inventory.*;
|
||||
import emu.grasscutter.game.mail.*;
|
||||
import emu.grasscutter.game.managers.*;
|
||||
import emu.grasscutter.game.managers.cooking.*;
|
||||
import emu.grasscutter.game.home.HomeWorld;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.Inventory;
|
||||
import emu.grasscutter.game.mail.Mail;
|
||||
import emu.grasscutter.game.mail.MailHandler;
|
||||
import emu.grasscutter.game.managers.FurnitureManager;
|
||||
import emu.grasscutter.game.managers.ResinManager;
|
||||
import emu.grasscutter.game.managers.SatiationManager;
|
||||
import emu.grasscutter.game.managers.SotSManager;
|
||||
import emu.grasscutter.game.managers.cooking.ActiveCookCompoundData;
|
||||
import emu.grasscutter.game.managers.cooking.CookingCompoundManager;
|
||||
import emu.grasscutter.game.managers.cooking.CookingManager;
|
||||
import emu.grasscutter.game.managers.deforestation.DeforestationManager;
|
||||
import emu.grasscutter.game.managers.energy.EnergyManager;
|
||||
import emu.grasscutter.game.managers.forging.*;
|
||||
import emu.grasscutter.game.managers.mapmark.*;
|
||||
import emu.grasscutter.game.managers.forging.ActiveForgeData;
|
||||
import emu.grasscutter.game.managers.forging.ForgingManager;
|
||||
import emu.grasscutter.game.managers.mapmark.MapMark;
|
||||
import emu.grasscutter.game.managers.mapmark.MapMarksManager;
|
||||
import emu.grasscutter.game.managers.stamina.StaminaManager;
|
||||
import emu.grasscutter.game.props.*;
|
||||
import emu.grasscutter.game.quest.QuestManager;
|
||||
@@ -47,12 +58,14 @@ import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
|
||||
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
||||
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
|
||||
import emu.grasscutter.plugin.api.PlayerHook;
|
||||
import emu.grasscutter.scripts.ScriptLoader;
|
||||
import emu.grasscutter.scripts.data.SceneRegion;
|
||||
import emu.grasscutter.server.event.player.*;
|
||||
import emu.grasscutter.server.game.*;
|
||||
import emu.grasscutter.server.game.GameSession.SessionState;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
import emu.grasscutter.utils.*;
|
||||
import emu.grasscutter.utils.DispatchUtils;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import emu.grasscutter.utils.helpers.DateHelper;
|
||||
import emu.grasscutter.utils.objects.FieldFetch;
|
||||
import it.unimi.dsi.fastutil.ints.*;
|
||||
@@ -79,6 +92,8 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
@Getter private int nameCardId = 210001;
|
||||
@Getter private Position position;
|
||||
@Getter @Setter private Position prevPos;
|
||||
@Getter @Setter private Position prevPosForHome;
|
||||
@Getter @Setter private int prevScene;
|
||||
@Getter private Position rotation;
|
||||
@Getter private PlayerBirthday birthday;
|
||||
@Getter private PlayerCodex codex;
|
||||
@@ -87,6 +102,7 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
@Getter @Setter private List<Integer> showNameCardList;
|
||||
@Getter private Map<Integer, Integer> properties;
|
||||
@Getter @Setter private int currentRealmId;
|
||||
@Getter @Setter private transient boolean isInEditMode;
|
||||
@Getter @Setter private int widgetId;
|
||||
@Getter @Setter private int sceneId;
|
||||
@Getter @Setter private int regionId;
|
||||
@@ -119,6 +135,8 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
@Transient private long nextGuid = 0;
|
||||
@Transient @Getter @Setter private int peerId;
|
||||
@Transient private World world; // Synchronized getter and setter
|
||||
@Transient @Getter @Setter private HomeWorld curHomeWorld;
|
||||
@Transient @Getter @Setter private boolean hasSentInitPacketInHome;
|
||||
@Transient private Scene scene; // Synchronized getter and setter
|
||||
@Transient @Getter private int weatherId = 0;
|
||||
@Transient @Getter private ClimateType climate = ClimateType.CLIMATE_SUNNY;
|
||||
@@ -173,6 +191,7 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
@Transient @Getter @Setter private SceneLoadState sceneLoadState = SceneLoadState.NONE;
|
||||
@Transient private boolean hasSentLoginPackets;
|
||||
@Transient private long nextSendPlayerLocTime = 0;
|
||||
@Getter private transient final Int2ObjectMap<EnterHomeRequest> enterHomeRequests;
|
||||
|
||||
private transient final Int2ObjectMap<CoopRequest> coopRequests; // Synchronized getter
|
||||
@Getter private transient final Queue<AttackResult> attackResults;
|
||||
@@ -209,6 +228,7 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
this.buffManager = new PlayerBuffManager(this);
|
||||
this.position = new Position(GameConstants.START_POSITION);
|
||||
this.prevPos = new Position();
|
||||
this.prevPosForHome = Position.ZERO;
|
||||
this.rotation = new Position(0, 307, 0);
|
||||
this.sceneId = 3;
|
||||
this.regionId = 1;
|
||||
@@ -245,6 +265,7 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
|
||||
this.attackResults = new LinkedBlockingQueue<>();
|
||||
this.coopRequests = new Int2ObjectOpenHashMap<>();
|
||||
this.enterHomeRequests = new Int2ObjectOpenHashMap<>();
|
||||
this.combatInvokeHandler = new InvokeHandler(PacketCombatInvocationsNotify.class);
|
||||
this.abilityInvokeHandler = new InvokeHandler(PacketAbilityInvocationsNotify.class);
|
||||
this.clientAbilityInitFinishHandler = new InvokeHandler(PacketClientAbilityInitFinishNotify.class);
|
||||
@@ -465,6 +486,18 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
this.seenRealmList.add(seenId);
|
||||
}
|
||||
|
||||
public Optional<GameHome> tryGetHome() {
|
||||
if (this.isOnline()) {
|
||||
return Optional.ofNullable(this.home);
|
||||
}
|
||||
|
||||
if (GameHome.doesHomeExist(this.getUid())) {
|
||||
this.home = GameHome.getByUid(this.getUid());
|
||||
}
|
||||
|
||||
return Optional.ofNullable(this.home);
|
||||
}
|
||||
|
||||
public int getExpeditionLimit() {
|
||||
final int CONST_VALUE_EXPEDITION_INIT_LIMIT = 2; // TODO: pull from ConstValueExcelConfigData.json
|
||||
int expeditionLimit = CONST_VALUE_EXPEDITION_INIT_LIMIT;
|
||||
@@ -687,7 +720,7 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
this.getQuestManager().forEachActiveQuest(quest -> {
|
||||
if (quest.getTriggerData() != null &&
|
||||
quest.getTriggers().containsKey(enterRegionName) &&
|
||||
region.getGroupId() == quest.getTriggerData().get(enterRegionName).getGroupId()) {
|
||||
region.getGroupId() == quest.getTriggerData().get(enterRegionName).getGroupId()) {
|
||||
// If trigger hasn't been fired yet
|
||||
if (!Boolean.TRUE.equals(quest.getTriggers().put(enterRegionName, true))) {
|
||||
this.getSession().send(new PacketServerCondMeetQuestListUpdateNotify());
|
||||
@@ -1175,6 +1208,21 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean expireEnterHomeRequest(EnterHomeRequest req) {
|
||||
return this.expireEnterHomeRequest(req, false);
|
||||
}
|
||||
|
||||
private boolean expireEnterHomeRequest(EnterHomeRequest req, boolean force) {
|
||||
if (!req.isExpired() && !force) return false;
|
||||
req.getRequester().sendPacket(new PacketPlayerApplyEnterHomeResultNotify(
|
||||
this.getUid(),
|
||||
this.getNickname(),
|
||||
false,
|
||||
PlayerApplyEnterHomeResultNotifyOuterClass.PlayerApplyEnterHomeResultNotify.Reason.SYSTEM_JUDGE));
|
||||
req.getRequester().sendPacket(new PacketTryEnterHomeRsp());
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized void onTick() {
|
||||
// Check ping
|
||||
if (this.getLastPingTime() > System.currentTimeMillis() + 60000) {
|
||||
@@ -1183,6 +1231,8 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
}
|
||||
// Check co-op requests
|
||||
this.getCoopRequests().values().removeIf(this::expireCoopRequest);
|
||||
// Check enter-home requests
|
||||
this.getEnterHomeRequests().values().removeIf(this::expireEnterHomeRequest);
|
||||
// Handle buff
|
||||
this.getBuffManager().onTick();
|
||||
// Ping
|
||||
@@ -1339,6 +1389,16 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
if (GameHome.HOME_SCENE_IDS.contains(this.getSceneId())) {
|
||||
this.setSceneId(this.prevScene <= 0 ? 3 : this.prevScene); // if the player in home, make the player go back.
|
||||
var pos = this.getPrevPosForHome();
|
||||
if (pos.equals(Position.ZERO)) {
|
||||
pos = ScriptLoader.getSceneMeta(this.getSceneId()).config.born_pos;
|
||||
}
|
||||
this.position.set(pos);
|
||||
}
|
||||
|
||||
// Create world
|
||||
World world = new World(this);
|
||||
world.addPlayer(this);
|
||||
@@ -1387,7 +1447,10 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
|
||||
this.furnitureManager.onLogin();
|
||||
// Home
|
||||
home = GameHome.getByUid(getUid());
|
||||
var homeWorld = this.getServer().getHomeWorldOrCreate(this);
|
||||
homeWorld.setHost(this); // synchronize player object if homeWorld already exists in the server.
|
||||
this.home = homeWorld.getHome();
|
||||
this.setCurHomeWorld(homeWorld);
|
||||
home.onOwnerLogin(this);
|
||||
// Activity
|
||||
this.activityManager = new ActivityManager(this);
|
||||
@@ -1411,7 +1474,6 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
|
||||
// register
|
||||
getServer().registerPlayer(this);
|
||||
getProfile().setPlayer(this); // Set online
|
||||
}
|
||||
|
||||
public void onLogout() {
|
||||
@@ -1432,9 +1494,10 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
|
||||
// Status stuff
|
||||
this.getProfile().syncWithCharacter(this);
|
||||
this.getProfile().setPlayer(null); // Set offline
|
||||
|
||||
this.getCoopRequests().clear();
|
||||
this.getEnterHomeRequests().values().forEach(req -> this.expireEnterHomeRequest(req, true));
|
||||
this.getEnterHomeRequests().clear();
|
||||
|
||||
// Save to db
|
||||
this.save();
|
||||
|
||||
@@ -1,31 +1,47 @@
|
||||
package emu.grasscutter.game.player;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||
|
||||
import dev.morphia.annotations.*;
|
||||
import emu.grasscutter.*;
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.avatar.AvatarSkillDepotData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.*;
|
||||
import emu.grasscutter.game.props.*;
|
||||
import emu.grasscutter.game.world.*;
|
||||
import emu.grasscutter.net.packet.*;
|
||||
import emu.grasscutter.net.proto.*;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.entity.EntityBaseGadget;
|
||||
import emu.grasscutter.game.entity.EntityTeam;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
import emu.grasscutter.game.props.EnterReason;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.world.Position;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.AbilityControlBlockOuterClass;
|
||||
import emu.grasscutter.net.proto.AbilityEmbryoOuterClass;
|
||||
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
|
||||
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
|
||||
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
||||
import emu.grasscutter.net.proto.TrialAvatarGrantRecordOuterClass.TrialAvatarGrantRecord.GrantReason;
|
||||
import emu.grasscutter.net.proto.VisionTypeOuterClass;
|
||||
import emu.grasscutter.server.event.entity.EntityCreationEvent;
|
||||
import emu.grasscutter.server.event.player.*;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import it.unimi.dsi.fastutil.ints.*;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.*;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||
|
||||
@Entity
|
||||
public final class TeamManager extends BasePlayerDataManager {
|
||||
@@ -350,8 +366,8 @@ public final class TeamManager extends BasePlayerDataManager {
|
||||
/** Updates all properties of the active team. */
|
||||
public void updateTeamProperties() {
|
||||
this.updateTeamResonances(); // Update team resonances.
|
||||
this.getPlayer()
|
||||
.sendPacket(new PacketSceneTeamUpdateNotify(this.getPlayer())); // Notify the player.
|
||||
this.getWorld()
|
||||
.broadcastPacket(new PacketSceneTeamUpdateNotify(this.getPlayer())); // Notify the all players in the world.
|
||||
|
||||
// Skill charges packet - Yes, this is official server behavior as of 2.6.0
|
||||
this.getActiveTeam().stream()
|
||||
|
||||
@@ -10,7 +10,10 @@ import java.util.stream.Stream;
|
||||
import lombok.Getter;
|
||||
|
||||
public enum ElementType implements IntValueEnum {
|
||||
None(0, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
||||
None(
|
||||
0,
|
||||
FightProperty.FIGHT_PROP_CUR_WIND_ENERGY,
|
||||
FightProperty.FIGHT_PROP_MAX_WIND_ENERGY),
|
||||
Fire(
|
||||
1,
|
||||
FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY,
|
||||
@@ -90,7 +93,7 @@ public enum ElementType implements IntValueEnum {
|
||||
@Getter private final int configHash;
|
||||
|
||||
ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp) {
|
||||
this(value, curEnergyProp, maxEnergyProp, 0, null, 1);
|
||||
this(value, curEnergyProp, maxEnergyProp, 0, null, 0);
|
||||
}
|
||||
|
||||
ElementType(
|
||||
|
||||
@@ -14,6 +14,7 @@ public class ItemUseUnlockHomeModule extends ItemUseInt {
|
||||
|
||||
@Override
|
||||
public boolean useItem(UseItemParams params) {
|
||||
return false;
|
||||
params.player.addRealmList(this.i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,11 @@ public class MultiplayerSystem extends BaseGameSystem {
|
||||
}
|
||||
|
||||
public boolean leaveCoop(Player player) {
|
||||
// Make sure player is not in home
|
||||
if (player.getCurHomeWorld().isInHome(player)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure player's world is multiplayer
|
||||
if (!player.getWorld().isMultiplayer()) {
|
||||
return false;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package emu.grasscutter.game.world;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.*;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameDepot;
|
||||
import emu.grasscutter.data.binout.SceneNpcBornEntry;
|
||||
import emu.grasscutter.data.binout.routes.Route;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
@@ -11,32 +12,44 @@ import emu.grasscutter.data.excels.scene.SceneData;
|
||||
import emu.grasscutter.data.excels.world.WorldLevelData;
|
||||
import emu.grasscutter.data.server.Grid;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.dungeons.*;
|
||||
import emu.grasscutter.game.dungeons.DungeonManager;
|
||||
import emu.grasscutter.game.dungeons.DungeonSettleListener;
|
||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
||||
import emu.grasscutter.game.entity.*;
|
||||
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.managers.blossom.BlossomManager;
|
||||
import emu.grasscutter.game.player.*;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.player.TeamInfo;
|
||||
import emu.grasscutter.game.props.*;
|
||||
import emu.grasscutter.game.quest.QuestGroupSuite;
|
||||
import emu.grasscutter.game.world.data.TeleportProperties;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.*;
|
||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||
import emu.grasscutter.net.proto.EnterTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass;
|
||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||
import emu.grasscutter.scripts.*;
|
||||
import emu.grasscutter.scripts.SceneIndexManager;
|
||||
import emu.grasscutter.scripts.SceneScriptManager;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.*;
|
||||
import emu.grasscutter.scripts.data.SceneBlock;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
import emu.grasscutter.server.event.entity.EntityCreationEvent;
|
||||
import emu.grasscutter.server.event.player.PlayerTeleportEvent;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
|
||||
import emu.grasscutter.utils.objects.KahnsSort;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.val;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.*;
|
||||
@@ -259,6 +272,13 @@ public final class Scene {
|
||||
this.removeEntity(gadget);
|
||||
}
|
||||
|
||||
// Remove player widget gadgets
|
||||
this.getEntities().values().stream()
|
||||
.filter(gameEntity -> gameEntity instanceof EntityVehicle)
|
||||
.map(gameEntity -> (EntityVehicle) gameEntity)
|
||||
.filter(entityVehicle -> entityVehicle.getOwner().equals(player))
|
||||
.forEach(entityVehicle -> this.removeEntity(entityVehicle, VisionType.VISION_TYPE_REMOVE));
|
||||
|
||||
// Deregister scene if not in use
|
||||
if (this.getPlayerCount() <= 0 && !this.dontDestroyWhenEmpty) {
|
||||
this.getScriptManager().onDestroy();
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
package emu.grasscutter.game.world;
|
||||
|
||||
import static emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType.SCRIPT;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.dungeon.DungeonData;
|
||||
import emu.grasscutter.game.entity.*;
|
||||
import emu.grasscutter.game.entity.EntityTeam;
|
||||
import emu.grasscutter.game.entity.EntityWorld;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.player.Player.SceneLoadState;
|
||||
import emu.grasscutter.game.props.*;
|
||||
import emu.grasscutter.game.props.EnterReason;
|
||||
import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||
import emu.grasscutter.game.world.data.TeleportProperties;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo.*;
|
||||
import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo.SystemHint;
|
||||
import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo.SystemHintType;
|
||||
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
|
||||
import emu.grasscutter.scripts.data.SceneConfig;
|
||||
import emu.grasscutter.server.event.player.PlayerTeleportEvent;
|
||||
@@ -19,14 +22,23 @@ import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
import emu.grasscutter.utils.ConversionUtils;
|
||||
import it.unimi.dsi.fastutil.ints.*;
|
||||
import java.util.*;
|
||||
import lombok.*;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.val;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType.SCRIPT;
|
||||
|
||||
public class World implements Iterable<Player> {
|
||||
@Getter private final GameServer server;
|
||||
@Getter private final Player host;
|
||||
@Getter private Player host;
|
||||
@Getter private final List<Player> players;
|
||||
@Getter private final Int2ObjectMap<Scene> scenes;
|
||||
|
||||
@@ -65,6 +77,15 @@ public class World implements Iterable<Player> {
|
||||
this.host.getServer().registerWorld(this);
|
||||
}
|
||||
|
||||
public World(GameServer server, Player owner) {
|
||||
this.server = server;
|
||||
this.host = owner;
|
||||
this.players = Collections.synchronizedList(new ArrayList<>());
|
||||
this.scenes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
|
||||
this.entity = new EntityWorld(this);
|
||||
this.lastUpdateTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public int getLevelEntityId() {
|
||||
return entity.getId();
|
||||
}
|
||||
@@ -90,6 +111,10 @@ public class World implements Iterable<Player> {
|
||||
this.worldLevel = worldLevel;
|
||||
}
|
||||
|
||||
protected synchronized void setHost(Player host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an associated scene by ID. Creates a new instance of the scene if it doesn't exist.
|
||||
*
|
||||
@@ -179,6 +204,58 @@ public class World implements Iterable<Player> {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void addPlayer(Player player, int newSceneId) {
|
||||
// Check if player already in
|
||||
if (this.getPlayers().contains(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove player from prev world
|
||||
if (player.getWorld() != null) {
|
||||
player.getWorld().removePlayer(player);
|
||||
}
|
||||
|
||||
// Register
|
||||
player.setWorld(this);
|
||||
this.getPlayers().add(player);
|
||||
|
||||
// Set player variables
|
||||
player.setPeerId(this.getNextPeerId());
|
||||
player.getTeamManager().setEntity(new EntityTeam(player));
|
||||
// player.getTeamManager().setEntityId(this.getNextEntityId(EntityIdType.TEAM));
|
||||
|
||||
// Copy main team to multiplayer team
|
||||
if (this.isMultiplayer()) {
|
||||
player
|
||||
.getTeamManager()
|
||||
.getMpTeam()
|
||||
.copyFrom(
|
||||
player.getTeamManager().getCurrentSinglePlayerTeamInfo(),
|
||||
player.getTeamManager().getMaxTeamSize());
|
||||
player.getTeamManager().setCurrentCharacterIndex(0);
|
||||
|
||||
if (player != this.getHost()) {
|
||||
this.broadcastPacket(
|
||||
new PacketPlayerChatNotify(
|
||||
player,
|
||||
0,
|
||||
SystemHint.newBuilder()
|
||||
.setType(SystemHintType.SYSTEM_HINT_TYPE_CHAT_ENTER_WORLD.getNumber())
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
// Add to scene
|
||||
player.setSceneId(newSceneId);
|
||||
Scene scene = this.getSceneById(player.getSceneId());
|
||||
scene.addPlayer(player);
|
||||
|
||||
// Info packet for other players
|
||||
if (this.getPlayers().size() > 1) {
|
||||
this.updatePlayerInfos(player);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removePlayer(Player player) {
|
||||
// Remove team entities
|
||||
player.sendPacket(
|
||||
@@ -389,7 +466,7 @@ public class World implements Iterable<Player> {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updatePlayerInfos(Player paramPlayer) {
|
||||
protected void updatePlayerInfos(Player paramPlayer) {
|
||||
for (Player player : this.getPlayers()) {
|
||||
// Dont send packets if player is logging in and filter out joining player
|
||||
if (!player.hasSentLoginPackets() || player == paramPlayer) {
|
||||
@@ -408,7 +485,7 @@ public class World implements Iterable<Player> {
|
||||
}
|
||||
|
||||
// Dont send packets if player is loading into the scene
|
||||
if (player.getSceneLoadState().getValue() < SceneLoadState.INIT.getValue()) {
|
||||
if (player.getSceneLoadState().getValue() >= SceneLoadState.INIT.getValue()) {
|
||||
// World player info packets
|
||||
player.getSession().send(new PacketWorldPlayerInfoNotify(this));
|
||||
player.getSession().send(new PacketScenePlayerInfoNotify(this));
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package emu.grasscutter.server.event.player;
|
||||
|
||||
import emu.grasscutter.game.home.GameHome;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.server.event.Cancellable;
|
||||
import emu.grasscutter.server.event.types.PlayerEvent;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public final class PlayerEnterHomeEvent extends PlayerEvent implements Cancellable {
|
||||
private final GameHome home;
|
||||
private final Player homeOwner;
|
||||
private final boolean isOtherHome;
|
||||
|
||||
public PlayerEnterHomeEvent(Player player, Player homeOwner, GameHome home) {
|
||||
super(player);
|
||||
|
||||
this.home = home;
|
||||
this.homeOwner = homeOwner;
|
||||
this.isOtherHome = this.getPlayer().equals(this.homeOwner);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package emu.grasscutter.server.event.player;
|
||||
|
||||
import emu.grasscutter.game.home.GameHome;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.server.event.types.PlayerEvent;
|
||||
|
||||
public class PlayerLeaveHomeEvent extends PlayerEvent {
|
||||
private final GameHome home;
|
||||
private final Player homeOwner;
|
||||
private final boolean isOtherHome;
|
||||
private final Reason reason;
|
||||
|
||||
public PlayerLeaveHomeEvent(Player player, Player homeOwner, GameHome home, Reason reason) {
|
||||
super(player);
|
||||
|
||||
this.homeOwner = homeOwner;
|
||||
this.home = home;
|
||||
this.reason = reason;
|
||||
this.isOtherHome = !this.getPlayer().equals(this.homeOwner);
|
||||
}
|
||||
|
||||
public enum Reason {
|
||||
PLAYER_LEAVE,
|
||||
KICKED
|
||||
}
|
||||
}
|
||||
@@ -1,45 +1,67 @@
|
||||
package emu.grasscutter.server.game;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.*;
|
||||
import static emu.grasscutter.utils.lang.Language.translate;
|
||||
|
||||
import emu.grasscutter.*;
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.Grasscutter.ServerRunMode;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.battlepass.BattlePassSystem;
|
||||
import emu.grasscutter.game.chat.*;
|
||||
import emu.grasscutter.game.chat.ChatSystem;
|
||||
import emu.grasscutter.game.chat.ChatSystemHandler;
|
||||
import emu.grasscutter.game.combine.CombineManger;
|
||||
import emu.grasscutter.game.drop.*;
|
||||
import emu.grasscutter.game.drop.DropSystem;
|
||||
import emu.grasscutter.game.drop.DropSystemLegacy;
|
||||
import emu.grasscutter.game.dungeons.DungeonSystem;
|
||||
import emu.grasscutter.game.expedition.ExpeditionSystem;
|
||||
import emu.grasscutter.game.gacha.GachaSystem;
|
||||
import emu.grasscutter.game.managers.cooking.*;
|
||||
import emu.grasscutter.game.home.HomeWorld;
|
||||
import emu.grasscutter.game.home.HomeWorldMPSystem;
|
||||
import emu.grasscutter.game.managers.cooking.CookingCompoundManager;
|
||||
import emu.grasscutter.game.managers.cooking.CookingManager;
|
||||
import emu.grasscutter.game.managers.energy.EnergyManager;
|
||||
import emu.grasscutter.game.managers.stamina.StaminaManager;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.quest.QuestSystem;
|
||||
import emu.grasscutter.game.shop.ShopSystem;
|
||||
import emu.grasscutter.game.systems.*;
|
||||
import emu.grasscutter.game.systems.AnnouncementSystem;
|
||||
import emu.grasscutter.game.systems.InventorySystem;
|
||||
import emu.grasscutter.game.systems.MultiplayerSystem;
|
||||
import emu.grasscutter.game.talk.TalkSystem;
|
||||
import emu.grasscutter.game.tower.TowerSystem;
|
||||
import emu.grasscutter.game.world.*;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.game.world.WorldDataSystem;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
|
||||
import emu.grasscutter.server.dispatch.DispatchClient;
|
||||
import emu.grasscutter.server.event.game.ServerTickEvent;
|
||||
import emu.grasscutter.server.event.internal.*;
|
||||
import emu.grasscutter.server.event.internal.ServerStartEvent;
|
||||
import emu.grasscutter.server.event.internal.ServerStopEvent;
|
||||
import emu.grasscutter.server.event.types.ServerEvent;
|
||||
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
|
||||
import emu.grasscutter.task.TaskMap;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import java.net.*;
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import kcp.highway.*;
|
||||
import lombok.*;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import kcp.highway.ChannelConfig;
|
||||
import kcp.highway.KcpServer;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
|
||||
import static emu.grasscutter.config.Configuration.GAME_INFO;
|
||||
import static emu.grasscutter.utils.lang.Language.translate;
|
||||
|
||||
@Getter
|
||||
public final class GameServer extends KcpServer implements Iterable<Player> {
|
||||
@@ -48,6 +70,7 @@ public final class GameServer extends KcpServer implements Iterable<Player> {
|
||||
private final GameServerPacketHandler packetHandler;
|
||||
private final Map<Integer, Player> players;
|
||||
private final Set<World> worlds;
|
||||
private final Int2ObjectMap<HomeWorld> homeWorlds;
|
||||
|
||||
@Setter private DispatchClient dispatchClient;
|
||||
|
||||
@@ -56,6 +79,7 @@ public final class GameServer extends KcpServer implements Iterable<Player> {
|
||||
private final GachaSystem gachaSystem;
|
||||
private final ShopSystem shopSystem;
|
||||
private final MultiplayerSystem multiplayerSystem;
|
||||
private final HomeWorldMPSystem homeWorldMPSystem;
|
||||
private final DungeonSystem dungeonSystem;
|
||||
private final ExpeditionSystem expeditionSystem;
|
||||
private final DropSystem dropSystem;
|
||||
@@ -98,11 +122,13 @@ public final class GameServer extends KcpServer implements Iterable<Player> {
|
||||
this.dispatchClient = null;
|
||||
this.players = null;
|
||||
this.worlds = null;
|
||||
this.homeWorlds = null;
|
||||
|
||||
this.inventorySystem = null;
|
||||
this.gachaSystem = null;
|
||||
this.shopSystem = null;
|
||||
this.multiplayerSystem = null;
|
||||
this.homeWorldMPSystem = null;
|
||||
this.dungeonSystem = null;
|
||||
this.expeditionSystem = null;
|
||||
this.dropSystem = null;
|
||||
@@ -140,6 +166,7 @@ public final class GameServer extends KcpServer implements Iterable<Player> {
|
||||
this.dispatchClient = new DispatchClient(GameServer.getDispatchUrl());
|
||||
this.players = new ConcurrentHashMap<>();
|
||||
this.worlds = Collections.synchronizedSet(new HashSet<>());
|
||||
this.homeWorlds = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
|
||||
|
||||
// Extra
|
||||
this.scheduler = new ServerTaskScheduler();
|
||||
@@ -150,6 +177,7 @@ public final class GameServer extends KcpServer implements Iterable<Player> {
|
||||
this.gachaSystem = new GachaSystem(this);
|
||||
this.shopSystem = new ShopSystem(this);
|
||||
this.multiplayerSystem = new MultiplayerSystem(this);
|
||||
this.homeWorldMPSystem = new HomeWorldMPSystem(this);
|
||||
this.dungeonSystem = new DungeonSystem(this);
|
||||
this.dropSystem = new DropSystem(this);
|
||||
this.dropSystemLegacy = new DropSystemLegacy(this);
|
||||
@@ -198,10 +226,12 @@ public final class GameServer extends KcpServer implements Iterable<Player> {
|
||||
getPlayers().put(player.getUid(), player);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Player getPlayerByUid(int id) {
|
||||
return this.getPlayerByUid(id, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Player getPlayerByUid(int id, boolean allowOfflinePlayers) {
|
||||
// Console check
|
||||
if (id == GameConstants.SERVER_CONSOLE_UID) {
|
||||
@@ -295,6 +325,15 @@ public final class GameServer extends KcpServer implements Iterable<Player> {
|
||||
world.save(); // Save the player's world
|
||||
}
|
||||
|
||||
public void registerHomeWorld(HomeWorld homeWorld) {
|
||||
this.getHomeWorlds().put(homeWorld.getOwnerUid(), homeWorld);
|
||||
this.registerWorld(homeWorld);
|
||||
}
|
||||
|
||||
public HomeWorld getHomeWorldOrCreate(Player owner) {
|
||||
return this.getHomeWorlds().computeIfAbsent(owner.getUid(), (uid) -> new HomeWorld(this, owner));
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (Grasscutter.getRunMode() == ServerRunMode.GAME_ONLY) {
|
||||
// Connect to dispatch server.
|
||||
|
||||
@@ -267,7 +267,7 @@ public final class RegionHandler implements Router {
|
||||
.setRegionInfo(RegionInfo.newBuilder())
|
||||
.setStopServer(
|
||||
StopServerInfo.newBuilder()
|
||||
.setUrl("https://discord.gg/grasscutters")
|
||||
.setUrl("https://discord.gg/T5vZU6UyeG")
|
||||
.setStopBeginTime((int) Instant.now().getEpochSecond())
|
||||
.setStopEndTime((int) Instant.now().getEpochSecond() + 1)
|
||||
.setContentMsg(
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketBackMyWorldRsp;
|
||||
|
||||
@@ -13,23 +12,15 @@ public class HandlerBackMyWorldReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
Scene scene = session.getPlayer().getScene();
|
||||
int prevScene = scene.getPrevScene();
|
||||
int prevScene = session.getPlayer().getPrevScene();
|
||||
|
||||
// Sanity check for switching between teapot realms
|
||||
if (prevScene >= 2000 && prevScene <= 2400) {
|
||||
prevScene = 3;
|
||||
}
|
||||
|
||||
session
|
||||
.getPlayer()
|
||||
.getWorld()
|
||||
.transferPlayerToScene(
|
||||
session.getPlayer(),
|
||||
prevScene,
|
||||
TeleportType.WAYPOINT,
|
||||
session.getPlayer().getPrevPos());
|
||||
boolean result = session.getServer().getHomeWorldMPSystem().leaveCoop(session.getPlayer(), prevScene);
|
||||
|
||||
session.send(new PacketBackMyWorldRsp());
|
||||
session.send(new PacketBackMyWorldRsp(result ? 0 : RetcodeOuterClass.Retcode.RET_FAIL_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
|
||||
// Handle movement
|
||||
EntityMoveInfo moveInfo = EntityMoveInfo.parseFrom(entry.getCombatData());
|
||||
GameEntity entity = session.getPlayer().getScene().getEntityById(moveInfo.getEntityId());
|
||||
if (entity != null) {
|
||||
if (entity != null && session.getPlayer().getSceneLoadState() != Player.SceneLoadState.LOADING) {
|
||||
// Move player
|
||||
MotionInfo motionInfo = moveInfo.getMotionInfo();
|
||||
MotionState motionState = motionInfo.getState();
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtAvatarEnterFocusNotifyOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketEvtAvatarEnterFocusNotify;
|
||||
|
||||
@Opcodes(PacketOpcodes.EvtAvatarEnterFocusNotify)
|
||||
public class HandlerEvtAvatarEnterFocusNotify extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtAvatarEnterFocusNotify(EvtAvatarEnterFocusNotifyOuterClass.EvtAvatarEnterFocusNotify.parseFrom(payload)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtAvatarExitFocusNotifyOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketEvtAvatarExitFocusNotify;
|
||||
|
||||
@Opcodes(PacketOpcodes.EvtAvatarExitFocusNotify)
|
||||
public class HandlerEvtAvatarExitFocusNotify extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtAvatarExitFocusNotify(EvtAvatarExitFocusNotifyOuterClass.EvtAvatarExitFocusNotify.parseFrom(payload)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtAvatarUpdateFocusNotifyOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketEvtAvatarUpdateFocusNotify;
|
||||
|
||||
@Opcodes(PacketOpcodes.EvtAvatarUpdateFocusNotify)
|
||||
public class HandlerEvtAvatarUpdateFocusNotify extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtAvatarUpdateFocusNotify(EvtAvatarUpdateFocusNotifyOuterClass.EvtAvatarUpdateFocusNotify.parseFrom(payload)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtBulletDeactiveNotifyOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketEvtBulletDeactiveNotify;
|
||||
|
||||
@Opcodes(PacketOpcodes.EvtBulletDeactiveNotify)
|
||||
public class HandlerEvtBulletDeactiveNotify extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtBulletDeactiveNotify(EvtBulletDeactiveNotifyOuterClass.EvtBulletDeactiveNotify.parseFrom(payload)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtBulletHitNotifyOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketEvtBulletHitNotify;
|
||||
|
||||
@Opcodes(PacketOpcodes.EvtBulletHitNotify)
|
||||
public class HandlerEvtBulletHitNotify extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtBulletHitNotify(EvtBulletHitNotifyOuterClass.EvtBulletHitNotify.parseFrom(payload)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtBulletMoveNotifyOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketEvtBulletMoveNotify;
|
||||
|
||||
@Opcodes(PacketOpcodes.EvtBulletMoveNotify)
|
||||
public class HandlerEvtBulletMoveNotify extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtBulletMoveNotify(EvtBulletMoveNotifyOuterClass.EvtBulletMoveNotify.parseFrom(payload)));
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public class HandlerHomeChangeBgmReq extends PacketHandler {
|
||||
home.getHomeSceneItem(session.getPlayer().getSceneId()).setHomeBgmId(homeBgmId);
|
||||
home.save();
|
||||
|
||||
session.send(new PacketHomeChangeBgmNotify(homeBgmId));
|
||||
session.getPlayer().getScene().broadcastPacket(new PacketHomeChangeBgmNotify(homeBgmId));
|
||||
session.send(new PacketHomeChangeBgmRsp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.HomeChangeEditModeReqOuterClass;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketHomeBasicInfoNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketHomeChangeEditModeRsp;
|
||||
@@ -17,6 +18,13 @@ public class HandlerHomeChangeEditModeReq extends PacketHandler {
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var req = HomeChangeEditModeReqOuterClass.HomeChangeEditModeReq.parseFrom(payload);
|
||||
|
||||
if (req.getIsEnterEditMode() && !session.getPlayer().getCurHomeWorld().getGuests().isEmpty()) {
|
||||
session.send(new PacketHomeChangeEditModeRsp(RetcodeOuterClass.Retcode.RET_HOME_HAS_GUEST_VALUE));
|
||||
return;
|
||||
}
|
||||
|
||||
session.getPlayer().setInEditMode(req.getIsEnterEditMode());
|
||||
session.getPlayer().getCurHomeWorld().getHome().save();
|
||||
session.send(new PacketHomePreChangeEditModeNotify(req.getIsEnterEditMode()));
|
||||
session.send(new PacketHomeBasicInfoNotify(session.getPlayer(), req.getIsEnterEditMode()));
|
||||
session.send(new PacketHomeComfortInfoNotify(session.getPlayer()));
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketHomeGetOnlineStatusRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.HomeGetOnlineStatusReq)
|
||||
public class HandlerHomeGetOnlineStatusReq extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
session.send(new PacketHomeGetOnlineStatusRsp(session.getPlayer().getCurHomeWorld().getGuests()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.HomeKickPlayerReqOuterClass;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketHomeKickPlayerRsp;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@Opcodes(PacketOpcodes.HomeKickPlayerReq)
|
||||
public class HandlerHomeKickPlayerReq extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var req = HomeKickPlayerReqOuterClass.HomeKickPlayerReq.parseFrom(payload);
|
||||
|
||||
var success = new AtomicBoolean();
|
||||
session.getPlayer().getCurHomeWorld().getGuests().stream()
|
||||
.filter(player -> player.getUid() == req.getTargetUid())
|
||||
.findFirst()
|
||||
.ifPresent(player -> {
|
||||
success.set(session.getServer().getHomeWorldMPSystem().kickPlayerFromHome(session.getPlayer(), player.getUid()));
|
||||
});
|
||||
|
||||
session.send(new PacketHomeKickPlayerRsp(success.get() ? 0 : RetcodeOuterClass.Retcode.RET_FAIL_VALUE, req));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.HomeSaveArrangementNoChangeReqOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketHomeSaveArrangementNoChangeRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.HomeSaveArrangementNoChangeReq)
|
||||
public class HandlerHomeSaveArrangementNoChangeReq extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
session.send(new PacketHomeSaveArrangementNoChangeRsp(HomeSaveArrangementNoChangeReqOuterClass.HomeSaveArrangementNoChangeReq.parseFrom(payload).getSceneId()));
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,29 @@ package emu.grasscutter.server.packet.recv;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.OtherPlayerEnterHomeNotifyOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketHomeMarkPointNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketHomeSceneInitFinishRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketOtherPlayerEnterOrLeaveHomeNotify;
|
||||
|
||||
@Opcodes(PacketOpcodes.HomeSceneInitFinishReq)
|
||||
public class HandlerHomeSceneInitFinishReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var curHomeWorld = session.getPlayer().getCurHomeWorld();
|
||||
|
||||
if (!session.getPlayer().isHasSentInitPacketInHome()) {
|
||||
session.getPlayer().setHasSentInitPacketInHome(true);
|
||||
|
||||
if (curHomeWorld.getHost().isOnline() && !curHomeWorld.getHost().equals(session.getPlayer())) {
|
||||
curHomeWorld.getHost().sendPacket(new PacketOtherPlayerEnterOrLeaveHomeNotify(session.getPlayer(), OtherPlayerEnterHomeNotifyOuterClass.OtherPlayerEnterHomeNotify.Reason.ENTER));
|
||||
}
|
||||
}
|
||||
|
||||
session.send(new PacketHomeMarkPointNotify(session.getPlayer()));
|
||||
|
||||
session.send(new PacketHomeSceneInitFinishRsp());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.game.world.Position;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
@@ -16,19 +14,16 @@ public class HandlerHomeSceneJumpReq extends PacketHandler {
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var req = HomeSceneJumpReqOuterClass.HomeSceneJumpReq.parseFrom(payload);
|
||||
|
||||
int realmId = 2000 + session.getPlayer().getCurrentRealmId();
|
||||
|
||||
var home = session.getPlayer().getHome();
|
||||
var world = session.getPlayer().getCurHomeWorld();
|
||||
var home = world.getHome();
|
||||
var owner = world.getHost();
|
||||
int realmId = 2000 + owner.getCurrentRealmId();
|
||||
var homeScene = home.getHomeSceneItem(realmId);
|
||||
home.save();
|
||||
|
||||
Scene scene =
|
||||
session
|
||||
.getPlayer()
|
||||
.getWorld()
|
||||
.getSceneById(req.getIsEnterRoomScene() ? homeScene.getRoomSceneId() : realmId);
|
||||
Position pos = scene.getScriptManager().getConfig().born_pos;
|
||||
Position rot = home.getSceneMap().get(scene.getId()).getBornRot();
|
||||
var scene = world.getSceneById(req.getIsEnterRoomScene() ? homeScene.getRoomSceneId() : realmId);
|
||||
var pos = scene.getScriptManager().getConfig().born_pos;
|
||||
var rot = home.getSceneMap().get(scene.getId()).getBornRot();
|
||||
|
||||
// Make player face correct direction when entering or exiting
|
||||
session.getPlayer().getRotation().set(rot);
|
||||
@@ -38,13 +33,7 @@ public class HandlerHomeSceneJumpReq extends PacketHandler {
|
||||
pos = home.getSceneMap().get(realmId).getBornPos();
|
||||
}
|
||||
|
||||
session
|
||||
.getPlayer()
|
||||
.getWorld()
|
||||
.transferPlayerToScene(
|
||||
session.getPlayer(),
|
||||
req.getIsEnterRoomScene() ? homeScene.getRoomSceneId() : realmId,
|
||||
pos);
|
||||
world.transferPlayerToScene(session.getPlayer(), req.getIsEnterRoomScene() ? homeScene.getRoomSceneId() : realmId, pos);
|
||||
|
||||
session.send(new PacketHomeSceneJumpRsp(req.getIsEnterRoomScene()));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import com.github.davidmoten.guavamini.Lists;
|
||||
import emu.grasscutter.game.home.HomeFurnitureItem;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.HomeTransferReqOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Opcodes(PacketOpcodes.HomeTransferReq)
|
||||
public class HandlerHomeTransferReq extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var req = HomeTransferReqOuterClass.HomeTransferReq.parseFrom(payload);
|
||||
var player = session.getPlayer();
|
||||
var home = player.getCurHomeWorld().getHome();
|
||||
var item = home.getHomeSceneItem(player.getSceneId());
|
||||
|
||||
if (req.getIsTransferToSafePoint()) {
|
||||
player.getCurHomeWorld().transferPlayerToScene(player, player.getSceneId(), item.getBornPos());
|
||||
} else {
|
||||
for (var homeBlockItem : item.getBlockItems().values()) {
|
||||
List<HomeFurnitureItem> items = Lists.newArrayList();
|
||||
items.addAll(homeBlockItem.getDeployFurnitureList());
|
||||
items.addAll(homeBlockItem.getPersistentFurnitureList());
|
||||
items.stream()
|
||||
.filter(homeFurnitureItem -> homeFurnitureItem.getGuid() == req.getGuid())
|
||||
.findFirst()
|
||||
.ifPresent(homeFurnitureItem -> {
|
||||
player.getCurHomeWorld().transferPlayerToScene(player, player.getSceneId(), homeFurnitureItem.getSpawnPos());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
session.send(new BasePacket(PacketOpcodes.HomeTransferRsp));
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.HomeUpdateArrangementInfoReqOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketHomeMarkPointNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketHomeUpdateArrangementInfoRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.HomeUpdateArrangementInfoReq)
|
||||
@@ -20,6 +21,8 @@ public class HandlerHomeUpdateArrangementInfoReq extends PacketHandler {
|
||||
|
||||
homeScene.update(req.getSceneArrangementInfo());
|
||||
|
||||
session.send(new PacketHomeMarkPointNotify(session.getPlayer()));
|
||||
|
||||
session.getPlayer().getHome().save();
|
||||
|
||||
session.send(new PacketHomeUpdateArrangementInfoRsp());
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.MassiveEntityElementOpBatchNotifyOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketMassiveEntityElementOpBatchNotify;
|
||||
|
||||
@Opcodes(PacketOpcodes.MassiveEntityElementOpBatchNotify)
|
||||
public class HandlerMassiveEntityElementOpBatchNotify extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketMassiveEntityElementOpBatchNotify(MassiveEntityElementOpBatchNotifyOuterClass.MassiveEntityElementOpBatchNotify.parseFrom(payload)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.PlayerApplyEnterHomeResultReqOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerApplyEnterHomeResultRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.PlayerApplyEnterHomeResultReq)
|
||||
public class HandlerPlayerApplyEnterHomeResultReq extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var req = PlayerApplyEnterHomeResultReqOuterClass.PlayerApplyEnterHomeResultReq.parseFrom(payload);
|
||||
|
||||
session.getServer().getHomeWorldMPSystem().acceptEnterHomeRequest(session.getPlayer(), req.getApplyUid(), req.getIsAgreed());
|
||||
session.send(new PacketPlayerApplyEnterHomeResultRsp(req.getApplyUid(), req.getIsAgreed()));
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import emu.grasscutter.net.proto.PlayerLoginReqOuterClass.PlayerLoginReq;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.game.GameSession.SessionState;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerLoginRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketTakeAchievementRewardReq;
|
||||
|
||||
@Opcodes(PacketOpcodes.PlayerLoginReq) // Sends initial data packets
|
||||
public class HandlerPlayerLoginReq extends PacketHandler {
|
||||
@@ -46,6 +45,5 @@ public class HandlerPlayerLoginReq extends PacketHandler {
|
||||
|
||||
// Final packet to tell client logging in is done
|
||||
session.send(new PacketPlayerLoginRsp(session));
|
||||
session.send(new PacketTakeAchievementRewardReq(session));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,20 @@ public class HandlerSceneTransToPointReq extends PacketHandler {
|
||||
var player = session.getPlayer();
|
||||
|
||||
ScenePointEntry scenePointEntry =
|
||||
GameData.getScenePointEntryById(req.getSceneId(), req.getPointId());
|
||||
GameData.getScenePointEntryById(req.getSceneId(), req.getPointId());
|
||||
|
||||
if (scenePointEntry != null) {
|
||||
if (player
|
||||
.getWorld()
|
||||
.transferPlayerToScene(
|
||||
player,
|
||||
req.getSceneId(),
|
||||
TeleportType.WAYPOINT,
|
||||
scenePointEntry.getPointData().getTranPos().clone())) {
|
||||
if (player.getCurHomeWorld().isInHome(player)) { // if the player is in home, make the player go back
|
||||
session.getServer().getHomeWorldMPSystem().leaveCoop(player, req.getSceneId(), scenePointEntry.getPointData().getTranPos().clone());
|
||||
session.send(new PacketSceneTransToPointRsp(player, req.getPointId(), req.getSceneId()));
|
||||
return;
|
||||
} else if (player
|
||||
.getWorld()
|
||||
.transferPlayerToScene(
|
||||
player,
|
||||
req.getSceneId(),
|
||||
TeleportType.WAYPOINT,
|
||||
scenePointEntry.getPointData().getTranPos().clone())) {
|
||||
session.send(new PacketSceneTransToPointRsp(player, req.getPointId(), req.getSceneId()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,72 +1,52 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.game.home.GameHome;
|
||||
import emu.grasscutter.game.world.Position;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.FriendEnterHomeOptionOuterClass;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||
import emu.grasscutter.net.proto.TryEnterHomeReqOuterClass;
|
||||
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketTryEnterHomeRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.TryEnterHomeReq)
|
||||
public class HandlerTryEnterHomeReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var req = TryEnterHomeReqOuterClass.TryEnterHomeReq.parseFrom(payload);
|
||||
var targetPlayer = session.getServer().getPlayerByUid(req.getTargetUid(), true);
|
||||
|
||||
if (req.getTargetUid() != session.getPlayer().getUid()) {
|
||||
// I hope that tomorrow there will be a hero who can support multiplayer mode and write code
|
||||
// like a poem
|
||||
var targetHome = GameHome.getByUid(req.getTargetUid());
|
||||
switch (targetHome.getEnterHomeOption()) {
|
||||
case FriendEnterHomeOptionOuterClass.FriendEnterHomeOption
|
||||
.FRIEND_ENTER_HOME_OPTION_NEED_CONFIRM_VALUE:
|
||||
if (!targetPlayer.isOnline()) {
|
||||
session.send(
|
||||
new PacketTryEnterHomeRsp(
|
||||
RetcodeOuterClass.Retcode.RET_HOME_OWNER_OFFLINE_VALUE, req.getTargetUid()));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case FriendEnterHomeOptionOuterClass.FriendEnterHomeOption
|
||||
.FRIEND_ENTER_HOME_OPTION_REFUSE_VALUE:
|
||||
session.send(
|
||||
new PacketTryEnterHomeRsp(
|
||||
RetcodeOuterClass.Retcode.RET_HOME_HOME_REFUSE_GUEST_ENTER_VALUE,
|
||||
req.getTargetUid()));
|
||||
return;
|
||||
case FriendEnterHomeOptionOuterClass.FriendEnterHomeOption
|
||||
.FRIEND_ENTER_HOME_OPTION_DIRECT_VALUE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (targetPlayer == null || !GameHome.doesHomeExist(targetPlayer.getUid())) {
|
||||
session.send(new PacketTryEnterHomeRsp());
|
||||
return;
|
||||
}
|
||||
|
||||
int realmId = 2000 + session.getPlayer().getCurrentRealmId();
|
||||
var targetHome = session.getServer().getHomeWorldOrCreate(targetPlayer).getHome();
|
||||
|
||||
var home = session.getPlayer().getHome();
|
||||
if (req.getTargetUid() != session.getPlayer().getUid()) {
|
||||
// I hope that tomorrow there will be a hero who can support multiplayer mode and write code
|
||||
// like a poem
|
||||
// A person who rote this comment, I DID IT!!!!!! by hamusuke.
|
||||
switch (targetHome.getEnterHomeOption()) {
|
||||
case FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.FRIEND_ENTER_HOME_OPTION_NEED_CONFIRM_VALUE -> {
|
||||
if (!targetPlayer.isOnline()) {
|
||||
session.send(new PacketTryEnterHomeRsp(RetcodeOuterClass.Retcode.RET_HOME_OWNER_OFFLINE_VALUE, req.getTargetUid()));
|
||||
} else {
|
||||
session.getServer().getHomeWorldMPSystem().sendEnterHomeRequest(session.getPlayer(), req.getTargetUid());
|
||||
}
|
||||
}
|
||||
case FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.FRIEND_ENTER_HOME_OPTION_REFUSE_VALUE -> {
|
||||
session.send(new PacketTryEnterHomeRsp(RetcodeOuterClass.Retcode.RET_HOME_HOME_REFUSE_GUEST_ENTER_VALUE, req.getTargetUid()));
|
||||
}
|
||||
case FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.FRIEND_ENTER_HOME_OPTION_DIRECT_VALUE -> {
|
||||
session.getServer().getHomeWorldMPSystem().enterHome(session.getPlayer(), targetPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
// prepare the default arrangement for first come in
|
||||
var homeScene = home.getHomeSceneItem(realmId);
|
||||
home.save();
|
||||
return;
|
||||
}
|
||||
|
||||
Scene scene = session.getPlayer().getWorld().getSceneById(realmId);
|
||||
Position pos = scene.getScriptManager().getConfig().born_pos;
|
||||
|
||||
boolean result =
|
||||
session
|
||||
.getPlayer()
|
||||
.getWorld()
|
||||
.transferPlayerToScene(session.getPlayer(), realmId, TeleportType.WAYPOINT, pos);
|
||||
if (result) session.send(new PacketTryEnterHomeRsp(req.getTargetUid()));
|
||||
session.getServer().getHomeWorldMPSystem().enterHome(session.getPlayer(), targetPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ import emu.grasscutter.net.proto.BackMyWorldRspOuterClass;
|
||||
|
||||
public class PacketBackMyWorldRsp extends BasePacket {
|
||||
|
||||
public PacketBackMyWorldRsp() {
|
||||
public PacketBackMyWorldRsp(int retcode) {
|
||||
super(PacketOpcodes.BackMyWorldRsp);
|
||||
|
||||
var proto = BackMyWorldRspOuterClass.BackMyWorldRsp.newBuilder();
|
||||
var proto = BackMyWorldRspOuterClass.BackMyWorldRsp.newBuilder().setRetcode(retcode);
|
||||
|
||||
this.setData(proto.build());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtAvatarEnterFocusNotifyOuterClass;
|
||||
|
||||
public class PacketEvtAvatarEnterFocusNotify extends BasePacket {
|
||||
public PacketEvtAvatarEnterFocusNotify(EvtAvatarEnterFocusNotifyOuterClass.EvtAvatarEnterFocusNotify notify) {
|
||||
super(PacketOpcodes.EvtAvatarEnterFocusNotify);
|
||||
|
||||
this.setData(EvtAvatarEnterFocusNotifyOuterClass.EvtAvatarEnterFocusNotify.newBuilder(notify));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtAvatarExitFocusNotifyOuterClass;
|
||||
|
||||
public class PacketEvtAvatarExitFocusNotify extends BasePacket {
|
||||
public PacketEvtAvatarExitFocusNotify(EvtAvatarExitFocusNotifyOuterClass.EvtAvatarExitFocusNotify notify) {
|
||||
super(PacketOpcodes.EvtAvatarExitFocusNotify);
|
||||
|
||||
this.setData(EvtAvatarExitFocusNotifyOuterClass.EvtAvatarExitFocusNotify.newBuilder(notify));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtAvatarUpdateFocusNotifyOuterClass;
|
||||
|
||||
public class PacketEvtAvatarUpdateFocusNotify extends BasePacket {
|
||||
public PacketEvtAvatarUpdateFocusNotify(EvtAvatarUpdateFocusNotifyOuterClass.EvtAvatarUpdateFocusNotify notify) {
|
||||
super(PacketOpcodes.EvtAvatarUpdateFocusNotify);
|
||||
|
||||
this.setData(EvtAvatarUpdateFocusNotifyOuterClass.EvtAvatarUpdateFocusNotify.newBuilder(notify));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtBulletDeactiveNotifyOuterClass;
|
||||
|
||||
public class PacketEvtBulletDeactiveNotify extends BasePacket {
|
||||
public PacketEvtBulletDeactiveNotify(EvtBulletDeactiveNotifyOuterClass.EvtBulletDeactiveNotify notify) {
|
||||
super(PacketOpcodes.EvtBulletDeactiveNotify);
|
||||
|
||||
this.setData(EvtBulletDeactiveNotifyOuterClass.EvtBulletDeactiveNotify.newBuilder(notify));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtBulletHitNotifyOuterClass;
|
||||
|
||||
public class PacketEvtBulletHitNotify extends BasePacket {
|
||||
public PacketEvtBulletHitNotify(EvtBulletHitNotifyOuterClass.EvtBulletHitNotify notify) {
|
||||
super(PacketOpcodes.EvtBulletHitNotify);
|
||||
|
||||
this.setData(EvtBulletHitNotifyOuterClass.EvtBulletHitNotify.newBuilder(notify));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtBulletMoveNotifyOuterClass;
|
||||
|
||||
public class PacketEvtBulletMoveNotify extends BasePacket {
|
||||
public PacketEvtBulletMoveNotify(EvtBulletMoveNotifyOuterClass.EvtBulletMoveNotify notify) {
|
||||
super(PacketOpcodes.EvtBulletMoveNotify);
|
||||
|
||||
this.setData(EvtBulletMoveNotifyOuterClass.EvtBulletMoveNotify.newBuilder(notify));
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_INFO;
|
||||
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.game.friends.Friendship;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.FriendBriefOuterClass.FriendBrief;
|
||||
import emu.grasscutter.net.proto.FriendEnterHomeOptionOuterClass;
|
||||
import emu.grasscutter.net.proto.FriendOnlineStateOuterClass.FriendOnlineState;
|
||||
import emu.grasscutter.net.proto.GetPlayerFriendListRspOuterClass.GetPlayerFriendListRsp;
|
||||
import emu.grasscutter.net.proto.PlatformTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_INFO;
|
||||
|
||||
public class PacketGetPlayerFriendListRsp extends BasePacket {
|
||||
|
||||
public PacketGetPlayerFriendListRsp(Player player) {
|
||||
@@ -33,6 +34,7 @@ public class PacketGetPlayerFriendListRsp extends BasePacket {
|
||||
.setParam(1)
|
||||
.setIsGameSource(true)
|
||||
.setPlatformType(PlatformTypeOuterClass.PlatformType.PLATFORM_TYPE_PC)
|
||||
.setFriendEnterHomeOptionValue(FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.FRIEND_ENTER_HOME_OPTION_REFUSE_VALUE)
|
||||
.build();
|
||||
|
||||
GetPlayerFriendListRsp.Builder proto =
|
||||
|
||||
@@ -11,26 +11,27 @@ public class PacketHomeBasicInfoNotify extends BasePacket {
|
||||
public PacketHomeBasicInfoNotify(Player player, boolean editMode) {
|
||||
super(PacketOpcodes.HomeBasicInfoNotify);
|
||||
|
||||
if (player.getCurrentRealmId() <= 0) {
|
||||
if (player.getCurrentRealmId() <= 0 && player.getCurHomeWorld() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var proto = HomeBasicInfoNotifyOuterClass.HomeBasicInfoNotify.newBuilder();
|
||||
|
||||
var sceneId = player.getCurrentRealmId() + 2000;
|
||||
var homeScene = player.getHome().getHomeSceneItem(sceneId);
|
||||
var home = player.getCurHomeWorld().getHome();
|
||||
var owner = home.getPlayer();
|
||||
var sceneId = owner.getCurrentRealmId() + 2000;
|
||||
var homeScene = home.getHomeSceneItem(sceneId);
|
||||
|
||||
proto.setBasicInfo(
|
||||
HomeBasicInfoOuterClass.HomeBasicInfo.newBuilder()
|
||||
.setCurModuleId(player.getCurrentRealmId())
|
||||
.setCurRoomSceneId(homeScene.getRoomSceneId())
|
||||
.setIsInEditMode(editMode)
|
||||
.setHomeOwnerUid(player.getUid())
|
||||
.setExp(player.getHome().getExp())
|
||||
.setLevel(player.getHome().getLevel())
|
||||
.setOwnerNickName(player.getNickname())
|
||||
// TODO limit shop
|
||||
.build());
|
||||
HomeBasicInfoOuterClass.HomeBasicInfo.newBuilder()
|
||||
.setCurModuleId(owner.getCurrentRealmId())
|
||||
.setCurRoomSceneId(homeScene.getRoomSceneId())
|
||||
.setIsInEditMode(editMode)
|
||||
.setHomeOwnerUid(owner.getUid())
|
||||
.setExp(home.getExp())
|
||||
.setLevel(home.getLevel())
|
||||
.setOwnerNickName(owner.getNickname())
|
||||
// TODO limit shop
|
||||
.build());
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
|
||||
@@ -15,4 +15,11 @@ public class PacketHomeChangeEditModeRsp extends BasePacket {
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
|
||||
public PacketHomeChangeEditModeRsp(int retcode) {
|
||||
super(PacketOpcodes.HomeChangeEditModeRsp);
|
||||
|
||||
this.setData(HomeChangeEditModeRspOuterClass.HomeChangeEditModeRsp.newBuilder()
|
||||
.setRetcode(retcode));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.HomeGetArrangementInfoRspOuterClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PacketHomeGetArrangementInfoRsp extends BasePacket {
|
||||
@@ -12,16 +13,12 @@ public class PacketHomeGetArrangementInfoRsp extends BasePacket {
|
||||
public PacketHomeGetArrangementInfoRsp(Player player, List<Integer> sceneIdList) {
|
||||
super(PacketOpcodes.HomeGetArrangementInfoRsp);
|
||||
|
||||
var home = player.getHome();
|
||||
|
||||
var homeScenes =
|
||||
sceneIdList.stream().map(home::getHomeSceneItem).map(HomeSceneItem::toProto).toList();
|
||||
|
||||
home.save();
|
||||
|
||||
var proto = HomeGetArrangementInfoRspOuterClass.HomeGetArrangementInfoRsp.newBuilder();
|
||||
|
||||
var home = player.getCurHomeWorld().getHome();
|
||||
var homeScenes =
|
||||
sceneIdList.stream().map(home::getHomeSceneItem).map(HomeSceneItem::toProto).toList();
|
||||
proto.addAllSceneArrangementInfoList(homeScenes);
|
||||
home.save();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.HomeGetOnlineStatusRspOuterClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PacketHomeGetOnlineStatusRsp extends BasePacket {
|
||||
public PacketHomeGetOnlineStatusRsp(List<Player> guests) {
|
||||
super(PacketOpcodes.HomeGetOnlineStatusRsp);
|
||||
|
||||
this.setData(HomeGetOnlineStatusRspOuterClass.HomeGetOnlineStatusRsp.newBuilder()
|
||||
.addAllPlayerInfoList(guests.stream().map(Player::getOnlinePlayerInfo).toList()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.HomeKickPlayerReqOuterClass;
|
||||
import emu.grasscutter.net.proto.HomeKickPlayerRspOuterClass;
|
||||
|
||||
public class PacketHomeKickPlayerRsp extends BasePacket {
|
||||
public PacketHomeKickPlayerRsp(int retcode, HomeKickPlayerReqOuterClass.HomeKickPlayerReq req) {
|
||||
super(PacketOpcodes.HomeKickPlayerRsp);
|
||||
|
||||
this.setData(HomeKickPlayerRspOuterClass.HomeKickPlayerRsp.newBuilder()
|
||||
.setIsKickAll(req.getIsKickAll())
|
||||
.setTargetUid(req.getTargetUid())
|
||||
.setRetcode(retcode));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.home.HomeBlockItem;
|
||||
import emu.grasscutter.game.home.HomeMarkPointProtoFactory;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.HomeMarkPointNotifyOuterClass;
|
||||
import emu.grasscutter.net.proto.HomeMarkPointSceneDataOuterClass;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class PacketHomeMarkPointNotify extends BasePacket {
|
||||
@@ -14,28 +17,30 @@ public class PacketHomeMarkPointNotify extends BasePacket {
|
||||
super(PacketOpcodes.HomeMarkPointNotify);
|
||||
|
||||
var proto = HomeMarkPointNotifyOuterClass.HomeMarkPointNotify.newBuilder();
|
||||
var world = player.getCurHomeWorld();
|
||||
var owner = world.getHost();
|
||||
var home = world.getHome();
|
||||
|
||||
if (player.getRealmList() == null) {
|
||||
if (owner.getRealmList() == null) {
|
||||
return;
|
||||
}
|
||||
for (var moduleId : player.getRealmList()) {
|
||||
var homeScene = player.getHome().getHomeSceneItem(moduleId + 2000);
|
||||
|
||||
for (var moduleId : owner.getRealmList()) {
|
||||
var homeScene = home.getHomeSceneItem(moduleId + 2000);
|
||||
|
||||
var markPointData =
|
||||
HomeMarkPointSceneDataOuterClass.HomeMarkPointSceneData.newBuilder()
|
||||
.setModuleId(moduleId)
|
||||
.setSceneId(moduleId + 2000)
|
||||
.setTeapotSpiritPos(homeScene.getDjinnPos().toProto());
|
||||
HomeMarkPointSceneDataOuterClass.HomeMarkPointSceneData.newBuilder()
|
||||
.setModuleId(moduleId)
|
||||
.setSceneId(moduleId + 2000)
|
||||
.setSafePointPos(homeScene.isRoom() ? VectorOuterClass.Vector.newBuilder().build() : world.getSceneById(moduleId + 2000).getScriptManager().getConfig().born_pos.toProto())
|
||||
.setTeapotSpiritPos(homeScene.isRoom() ? VectorOuterClass.Vector.newBuilder().build() : homeScene.getDjinnPos().toProto());
|
||||
|
||||
// Now it only supports the teleport point
|
||||
// TODO add more types
|
||||
var marks =
|
||||
homeScene.getBlockItems().values().stream()
|
||||
.map(HomeBlockItem::getDeployFurnitureList)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(i -> i.getFurnitureId() == 373501)
|
||||
.map(x -> x.toMarkPointProto(3))
|
||||
.toList();
|
||||
var marks = homeScene.getBlockItems().values().stream()
|
||||
.map(HomeBlockItem::getMarkPointProtoFactories)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(HomeMarkPointProtoFactory::isProtoConvertible)
|
||||
.map(HomeMarkPointProtoFactory::toMarkPointProto)
|
||||
.toList();
|
||||
|
||||
markPointData.addAllFurnitureList(marks);
|
||||
proto.addMarkPointDataList(markPointData);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.HomeSaveArrangementNoChangeRspOuterClass;
|
||||
|
||||
public class PacketHomeSaveArrangementNoChangeRsp extends BasePacket {
|
||||
public PacketHomeSaveArrangementNoChangeRsp(int sceneId) {
|
||||
super(PacketOpcodes.HomeSaveArrangementNoChangeRsp);
|
||||
|
||||
this.setData(HomeSaveArrangementNoChangeRspOuterClass.HomeSaveArrangementNoChangeRsp.newBuilder()
|
||||
.setSceneId(sceneId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.MassiveEntityElementOpBatchNotifyOuterClass;
|
||||
|
||||
public class PacketMassiveEntityElementOpBatchNotify extends BasePacket {
|
||||
public PacketMassiveEntityElementOpBatchNotify(MassiveEntityElementOpBatchNotifyOuterClass.MassiveEntityElementOpBatchNotify notify) {
|
||||
super(PacketOpcodes.MassiveEntityElementOpBatchNotify);
|
||||
|
||||
this.setData(MassiveEntityElementOpBatchNotifyOuterClass.MassiveEntityElementOpBatchNotify.newBuilder(notify));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.OtherPlayerEnterHomeNotifyOuterClass;
|
||||
|
||||
public class PacketOtherPlayerEnterOrLeaveHomeNotify extends BasePacket {
|
||||
public PacketOtherPlayerEnterOrLeaveHomeNotify(Player enterer, OtherPlayerEnterHomeNotifyOuterClass.OtherPlayerEnterHomeNotify.Reason reason) {
|
||||
super(PacketOpcodes.OtherPlayerEnterHomeNotify);
|
||||
|
||||
this.setData(OtherPlayerEnterHomeNotifyOuterClass.OtherPlayerEnterHomeNotify.newBuilder()
|
||||
.setNickname(enterer.getNickname())
|
||||
.setReason(reason));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.PlayerApplyEnterHomeNotifyOuterClass;
|
||||
|
||||
public class PacketPlayerApplyEnterHomeNotify extends BasePacket {
|
||||
public PacketPlayerApplyEnterHomeNotify(Player requester) {
|
||||
super(PacketOpcodes.PlayerApplyEnterHomeNotify);
|
||||
|
||||
this.setData(PlayerApplyEnterHomeNotifyOuterClass.PlayerApplyEnterHomeNotify.newBuilder()
|
||||
.setSrcPlayerInfo(requester.getOnlinePlayerInfo()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.PlayerApplyEnterHomeResultNotifyOuterClass;
|
||||
|
||||
public class PacketPlayerApplyEnterHomeResultNotify extends BasePacket {
|
||||
public PacketPlayerApplyEnterHomeResultNotify(int targetUid, String nickname, boolean agreed, PlayerApplyEnterHomeResultNotifyOuterClass.PlayerApplyEnterHomeResultNotify.Reason reason) {
|
||||
super(PacketOpcodes.PlayerApplyEnterHomeResultNotify);
|
||||
|
||||
this.setData(PlayerApplyEnterHomeResultNotifyOuterClass.PlayerApplyEnterHomeResultNotify.newBuilder()
|
||||
.setTargetUid(targetUid)
|
||||
.setTargetNickname(nickname)
|
||||
.setIsAgreed(agreed)
|
||||
.setReason(reason));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.PlayerApplyEnterHomeResultRspOuterClass;
|
||||
|
||||
public class PacketPlayerApplyEnterHomeResultRsp extends BasePacket {
|
||||
public PacketPlayerApplyEnterHomeResultRsp(int uid, boolean agreed) {
|
||||
super(PacketOpcodes.PlayerApplyEnterHomeResultRsp);
|
||||
|
||||
this.setData(PlayerApplyEnterHomeResultRspOuterClass.PlayerApplyEnterHomeResultRsp.newBuilder()
|
||||
.setApplyUid(uid)
|
||||
.setIsAgreed(agreed));
|
||||
}
|
||||
}
|
||||
@@ -21,30 +21,30 @@ public class PacketPlayerEnterSceneNotify extends BasePacket {
|
||||
player.setEnterSceneToken(Utils.randomRange(1000, 99999));
|
||||
|
||||
var proto =
|
||||
PlayerEnterSceneNotify.newBuilder()
|
||||
.setSceneId(player.getSceneId())
|
||||
.setPos(player.getPosition().toProto())
|
||||
.setSceneBeginTime(System.currentTimeMillis())
|
||||
.setType(EnterType.ENTER_TYPE_SELF)
|
||||
.setTargetUid(player.getUid())
|
||||
.setEnterSceneToken(player.getEnterSceneToken())
|
||||
.setWorldLevel(player.getWorldLevel())
|
||||
.setEnterReason(EnterReason.Login.getValue())
|
||||
.setIsFirstLoginEnterScene(player.isFirstLoginEnterScene())
|
||||
.setWorldType(1)
|
||||
.setSceneTransaction(
|
||||
"3-"
|
||||
+ player.getUid()
|
||||
+ "-"
|
||||
+ (int) (System.currentTimeMillis() / 1000)
|
||||
+ "-"
|
||||
+ 18402);
|
||||
PlayerEnterSceneNotify.newBuilder()
|
||||
.setSceneId(player.getSceneId())
|
||||
.setPos(player.getPosition().toProto())
|
||||
.setSceneBeginTime(System.currentTimeMillis())
|
||||
.setType(EnterType.ENTER_TYPE_SELF)
|
||||
.setTargetUid(player.getUid())
|
||||
.setEnterSceneToken(player.getEnterSceneToken())
|
||||
.setWorldLevel(player.getWorldLevel())
|
||||
.setEnterReason(EnterReason.Login.getValue())
|
||||
.setIsFirstLoginEnterScene(player.isFirstLoginEnterScene())
|
||||
.setWorldType(1)
|
||||
.setSceneTransaction(
|
||||
"3-"
|
||||
+ player.getUid()
|
||||
+ "-"
|
||||
+ (int) (System.currentTimeMillis() / 1000)
|
||||
+ "-"
|
||||
+ 18402);
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
|
||||
public PacketPlayerEnterSceneNotify(
|
||||
Player player, EnterType type, EnterReason reason, int newScene, Position newPos) {
|
||||
Player player, EnterType type, EnterReason reason, int newScene, Position newPos) {
|
||||
this(player, player, type, reason, newScene, newPos);
|
||||
}
|
||||
|
||||
@@ -53,52 +53,52 @@ public class PacketPlayerEnterSceneNotify extends BasePacket {
|
||||
}
|
||||
|
||||
public PacketPlayerEnterSceneNotify(
|
||||
Player player,
|
||||
Player target,
|
||||
EnterType type,
|
||||
EnterReason reason,
|
||||
int newScene,
|
||||
Position newPos) {
|
||||
Player player,
|
||||
Player target,
|
||||
EnterType type,
|
||||
EnterReason reason,
|
||||
int newScene,
|
||||
Position newPos) {
|
||||
this(
|
||||
player,
|
||||
target,
|
||||
TeleportProperties.builder()
|
||||
.enterType(type)
|
||||
.enterReason(reason)
|
||||
.sceneId(newScene)
|
||||
.teleportTo(newPos)
|
||||
.build());
|
||||
player,
|
||||
target,
|
||||
TeleportProperties.builder()
|
||||
.enterType(type)
|
||||
.enterReason(reason)
|
||||
.sceneId(newScene)
|
||||
.teleportTo(newPos)
|
||||
.build());
|
||||
}
|
||||
|
||||
// Teleport or go somewhere
|
||||
public PacketPlayerEnterSceneNotify(
|
||||
Player player, Player target, TeleportProperties teleportProperties) {
|
||||
Player player, Player target, TeleportProperties teleportProperties) {
|
||||
super(PacketOpcodes.PlayerEnterSceneNotify);
|
||||
|
||||
player.setSceneLoadState(SceneLoadState.LOADING);
|
||||
player.setEnterSceneToken(Utils.randomRange(1000, 99999));
|
||||
|
||||
var proto =
|
||||
PlayerEnterSceneNotify.newBuilder()
|
||||
.setPrevSceneId(player.getSceneId())
|
||||
.setPrevPos(player.getPosition().toProto())
|
||||
.setSceneId(teleportProperties.getSceneId())
|
||||
.setPos(teleportProperties.getTeleportTo().toProto())
|
||||
.setSceneBeginTime(System.currentTimeMillis())
|
||||
.setType(teleportProperties.getEnterType())
|
||||
.setTargetUid(target.getUid())
|
||||
.setEnterSceneToken(player.getEnterSceneToken())
|
||||
.setWorldLevel(target.getWorld().getWorldLevel())
|
||||
.setEnterReason(teleportProperties.getEnterReason().getValue())
|
||||
.setWorldType(1)
|
||||
.setSceneTransaction(
|
||||
teleportProperties.getSceneId()
|
||||
+ "-"
|
||||
+ target.getUid()
|
||||
+ "-"
|
||||
+ (int) (System.currentTimeMillis() / 1000)
|
||||
+ "-"
|
||||
+ 18402);
|
||||
PlayerEnterSceneNotify.newBuilder()
|
||||
.setPrevSceneId(player.getSceneId())
|
||||
.setPrevPos(player.getPosition().toProto())
|
||||
.setSceneId(teleportProperties.getSceneId())
|
||||
.setPos(teleportProperties.getTeleportTo().toProto())
|
||||
.setSceneBeginTime(System.currentTimeMillis())
|
||||
.setType(teleportProperties.getEnterType())
|
||||
.setTargetUid(target.getUid())
|
||||
.setEnterSceneToken(player.getEnterSceneToken())
|
||||
.setWorldLevel(target.getWorld().getWorldLevel())
|
||||
.setEnterReason(teleportProperties.getEnterReason().getValue())
|
||||
.setWorldType(1)
|
||||
.setSceneTransaction(
|
||||
teleportProperties.getSceneId()
|
||||
+ "-"
|
||||
+ target.getUid()
|
||||
+ "-"
|
||||
+ (int) (System.currentTimeMillis() / 1000)
|
||||
+ "-"
|
||||
+ 18402);
|
||||
|
||||
// Apply the dungeon ID to the packet if it's a dungeon.
|
||||
if (teleportProperties.getDungeonId() != 0) {
|
||||
@@ -107,4 +107,36 @@ public class PacketPlayerEnterSceneNotify extends BasePacket {
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
|
||||
// Go home
|
||||
public PacketPlayerEnterSceneNotify(
|
||||
Player player, int targetUid, TeleportProperties teleportProperties, boolean other) {
|
||||
super(PacketOpcodes.PlayerEnterSceneNotify);
|
||||
|
||||
player.setSceneLoadState(SceneLoadState.LOADING);
|
||||
player.setEnterSceneToken(Utils.randomRange(1000, 99999));
|
||||
|
||||
var proto =
|
||||
PlayerEnterSceneNotify.newBuilder()
|
||||
.setPrevSceneId(player.getSceneId())
|
||||
.setPrevPos(player.getPosition().toProto())
|
||||
.setSceneId(teleportProperties.getSceneId())
|
||||
.setPos(teleportProperties.getTeleportTo().toProto())
|
||||
.setSceneBeginTime(System.currentTimeMillis())
|
||||
.setType(other ? EnterType.ENTER_TYPE_OTHER_HOME : EnterType.ENTER_TYPE_SELF_HOME)
|
||||
.setTargetUid(targetUid)
|
||||
.setEnterSceneToken(player.getEnterSceneToken())
|
||||
.setEnterReason(teleportProperties.getEnterReason().getValue())
|
||||
.setWorldType(64)
|
||||
.setSceneTransaction(
|
||||
teleportProperties.getSceneId()
|
||||
+ "-"
|
||||
+ targetUid
|
||||
+ "-"
|
||||
+ (int) (System.currentTimeMillis() / 1000)
|
||||
+ "-"
|
||||
+ 27573);
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.PlayerHomeCompInfoNotifyOuterClass;
|
||||
import emu.grasscutter.net.proto.PlayerHomeCompInfoOuterClass;
|
||||
import java.util.List;
|
||||
|
||||
public class PacketPlayerHomeCompInfoNotify extends BasePacket {
|
||||
|
||||
@@ -22,7 +21,8 @@ public class PacketPlayerHomeCompInfoNotify extends BasePacket {
|
||||
.setCompInfo(
|
||||
PlayerHomeCompInfoOuterClass.PlayerHomeCompInfo.newBuilder()
|
||||
.addAllUnlockedModuleIdList(player.getRealmList())
|
||||
.addAllLevelupRewardGotLevelList(List.of(1)) // Hardcoded
|
||||
.addAllLevelupRewardGotLevelList(player.getHomeRewardedLevels())
|
||||
.addAllSeenModuleIdList(player.getSeenRealmList())
|
||||
.setFriendEnterHomeOptionValue(player.getHome().getEnterHomeOption())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.PlayerPreEnterMpNotifyOuterClass;
|
||||
|
||||
public class PacketPlayerPreEnterMpNotify extends BasePacket {
|
||||
public PacketPlayerPreEnterMpNotify(Player player) {
|
||||
super(PacketOpcodes.PlayerPreEnterMpNotify);
|
||||
|
||||
this.setData(PlayerPreEnterMpNotifyOuterClass.PlayerPreEnterMpNotify.newBuilder()
|
||||
.setUid(player.getUid())
|
||||
.setNickname(player.getNickname())
|
||||
.setState(PlayerPreEnterMpNotifyOuterClass.PlayerPreEnterMpNotify.State.START));
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public class PacketTryEnterHomeRsp extends BasePacket {
|
||||
|
||||
TryEnterHomeRspOuterClass.TryEnterHomeRsp proto =
|
||||
TryEnterHomeRspOuterClass.TryEnterHomeRsp.newBuilder()
|
||||
.setRetcode(RetcodeOuterClass.Retcode.RET_SVR_ERROR_VALUE)
|
||||
.setRetcode(RetcodeOuterClass.Retcode.RET_HOME_APPLY_ENTER_OTHER_HOME_FAIL_VALUE)
|
||||
.build();
|
||||
|
||||
this.setData(proto);
|
||||
@@ -23,7 +23,6 @@ public class PacketTryEnterHomeRsp extends BasePacket {
|
||||
|
||||
TryEnterHomeRspOuterClass.TryEnterHomeRsp proto =
|
||||
TryEnterHomeRspOuterClass.TryEnterHomeRsp.newBuilder()
|
||||
.setRetcode(0)
|
||||
.setTargetUid(uid)
|
||||
.build();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user