diff --git a/src/generated/main/java/emu/grasscutter/net/proto/HomeBasicInfoOuterClass.java b/src/generated/main/java/emu/grasscutter/net/proto/HomeBasicInfoOuterClass.java index 040cf4ee3..0d38ac20f 100644 --- a/src/generated/main/java/emu/grasscutter/net/proto/HomeBasicInfoOuterClass.java +++ b/src/generated/main/java/emu/grasscutter/net/proto/HomeBasicInfoOuterClass.java @@ -43,17 +43,17 @@ public final class HomeBasicInfoOuterClass { boolean getIsInEditMode(); /** - * uint32 cur_module_id = 13; - * @return The curModuleId. - */ - int getCurModuleId(); - - /** - * uint32 cur_room_scene_id = 8; + * uint32 cur_room_scene_id = 13; * @return The curRoomSceneId. */ int getCurRoomSceneId(); + /** + * uint32 cur_module_id = 8; + * @return The curModuleId. + */ + int getCurModuleId(); + /** * uint64 exp = 10; * @return The exp. @@ -139,7 +139,7 @@ public final class HomeBasicInfoOuterClass { } case 64: { - curRoomSceneId_ = input.readUInt32(); + curModuleId_ = input.readUInt32(); break; } case 72: { @@ -159,7 +159,7 @@ public final class HomeBasicInfoOuterClass { } case 104: { - curModuleId_ = input.readUInt32(); + curRoomSceneId_ = input.readUInt32(); break; } case 112: { @@ -272,21 +272,10 @@ public final class HomeBasicInfoOuterClass { return isInEditMode_; } - public static final int CUR_MODULE_ID_FIELD_NUMBER = 13; - private int curModuleId_; - /** - * uint32 cur_module_id = 13; - * @return The curModuleId. - */ - @java.lang.Override - public int getCurModuleId() { - return curModuleId_; - } - - public static final int CUR_ROOM_SCENE_ID_FIELD_NUMBER = 8; + public static final int CUR_ROOM_SCENE_ID_FIELD_NUMBER = 13; private int curRoomSceneId_; /** - * uint32 cur_room_scene_id = 8; + * uint32 cur_room_scene_id = 13; * @return The curRoomSceneId. */ @java.lang.Override @@ -294,6 +283,17 @@ public final class HomeBasicInfoOuterClass { return curRoomSceneId_; } + public static final int CUR_MODULE_ID_FIELD_NUMBER = 8; + private int curModuleId_; + /** + * uint32 cur_module_id = 8; + * @return The curModuleId. + */ + @java.lang.Override + public int getCurModuleId() { + return curModuleId_; + } + public static final int EXP_FIELD_NUMBER = 10; private long exp_; /** @@ -359,8 +359,8 @@ public final class HomeBasicInfoOuterClass { if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(ownerNickName_)) { com.google.protobuf.GeneratedMessageV3.writeString(output, 5, ownerNickName_); } - if (curRoomSceneId_ != 0) { - output.writeUInt32(8, curRoomSceneId_); + if (curModuleId_ != 0) { + output.writeUInt32(8, curModuleId_); } if (isInEditMode_ != false) { output.writeBool(9, isInEditMode_); @@ -371,8 +371,8 @@ public final class HomeBasicInfoOuterClass { if (level_ != 0) { output.writeUInt32(11, level_); } - if (curModuleId_ != 0) { - output.writeUInt32(13, curModuleId_); + if (curRoomSceneId_ != 0) { + output.writeUInt32(13, curRoomSceneId_); } if (homeOwnerUid_ != 0) { output.writeUInt32(14, homeOwnerUid_); @@ -392,9 +392,9 @@ public final class HomeBasicInfoOuterClass { if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(ownerNickName_)) { size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, ownerNickName_); } - if (curRoomSceneId_ != 0) { + if (curModuleId_ != 0) { size += com.google.protobuf.CodedOutputStream - .computeUInt32Size(8, curRoomSceneId_); + .computeUInt32Size(8, curModuleId_); } if (isInEditMode_ != false) { size += com.google.protobuf.CodedOutputStream @@ -408,9 +408,9 @@ public final class HomeBasicInfoOuterClass { size += com.google.protobuf.CodedOutputStream .computeUInt32Size(11, level_); } - if (curModuleId_ != 0) { + if (curRoomSceneId_ != 0) { size += com.google.protobuf.CodedOutputStream - .computeUInt32Size(13, curModuleId_); + .computeUInt32Size(13, curRoomSceneId_); } if (homeOwnerUid_ != 0) { size += com.google.protobuf.CodedOutputStream @@ -441,10 +441,10 @@ public final class HomeBasicInfoOuterClass { .equals(other.getOwnerNickName())) return false; if (getIsInEditMode() != other.getIsInEditMode()) return false; - if (getCurModuleId() - != other.getCurModuleId()) return false; if (getCurRoomSceneId() != other.getCurRoomSceneId()) return false; + if (getCurModuleId() + != other.getCurModuleId()) return false; if (getExp() != other.getExp()) return false; if (getHomeOwnerUid() @@ -472,10 +472,10 @@ public final class HomeBasicInfoOuterClass { hash = (37 * hash) + IS_IN_EDIT_MODE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( getIsInEditMode()); - hash = (37 * hash) + CUR_MODULE_ID_FIELD_NUMBER; - hash = (53 * hash) + getCurModuleId(); hash = (37 * hash) + CUR_ROOM_SCENE_ID_FIELD_NUMBER; hash = (53 * hash) + getCurRoomSceneId(); + hash = (37 * hash) + CUR_MODULE_ID_FIELD_NUMBER; + hash = (53 * hash) + getCurModuleId(); hash = (37 * hash) + EXP_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( getExp()); @@ -628,10 +628,10 @@ public final class HomeBasicInfoOuterClass { isInEditMode_ = false; - curModuleId_ = 0; - curRoomSceneId_ = 0; + curModuleId_ = 0; + exp_ = 0L; homeOwnerUid_ = 0; @@ -671,8 +671,8 @@ public final class HomeBasicInfoOuterClass { result.level_ = level_; result.ownerNickName_ = ownerNickName_; result.isInEditMode_ = isInEditMode_; - result.curModuleId_ = curModuleId_; result.curRoomSceneId_ = curRoomSceneId_; + result.curModuleId_ = curModuleId_; result.exp_ = exp_; result.homeOwnerUid_ = homeOwnerUid_; if (limitedShopInfoBuilder_ == null) { @@ -738,12 +738,12 @@ public final class HomeBasicInfoOuterClass { if (other.getIsInEditMode() != false) { setIsInEditMode(other.getIsInEditMode()); } - if (other.getCurModuleId() != 0) { - setCurModuleId(other.getCurModuleId()); - } if (other.getCurRoomSceneId() != 0) { setCurRoomSceneId(other.getCurRoomSceneId()); } + if (other.getCurModuleId() != 0) { + setCurModuleId(other.getCurModuleId()); + } if (other.getExp() != 0L) { setExp(other.getExp()); } @@ -920,40 +920,9 @@ public final class HomeBasicInfoOuterClass { return this; } - private int curModuleId_ ; - /** - * uint32 cur_module_id = 13; - * @return The curModuleId. - */ - @java.lang.Override - public int getCurModuleId() { - return curModuleId_; - } - /** - * uint32 cur_module_id = 13; - * @param value The curModuleId to set. - * @return This builder for chaining. - */ - public Builder setCurModuleId(int value) { - - curModuleId_ = value; - onChanged(); - return this; - } - /** - * uint32 cur_module_id = 13; - * @return This builder for chaining. - */ - public Builder clearCurModuleId() { - - curModuleId_ = 0; - onChanged(); - return this; - } - private int curRoomSceneId_ ; /** - * uint32 cur_room_scene_id = 8; + * uint32 cur_room_scene_id = 13; * @return The curRoomSceneId. */ @java.lang.Override @@ -961,7 +930,7 @@ public final class HomeBasicInfoOuterClass { return curRoomSceneId_; } /** - * uint32 cur_room_scene_id = 8; + * uint32 cur_room_scene_id = 13; * @param value The curRoomSceneId to set. * @return This builder for chaining. */ @@ -972,7 +941,7 @@ public final class HomeBasicInfoOuterClass { return this; } /** - * uint32 cur_room_scene_id = 8; + * uint32 cur_room_scene_id = 13; * @return This builder for chaining. */ public Builder clearCurRoomSceneId() { @@ -982,6 +951,37 @@ public final class HomeBasicInfoOuterClass { return this; } + private int curModuleId_ ; + /** + * uint32 cur_module_id = 8; + * @return The curModuleId. + */ + @java.lang.Override + public int getCurModuleId() { + return curModuleId_; + } + /** + * uint32 cur_module_id = 8; + * @param value The curModuleId to set. + * @return This builder for chaining. + */ + public Builder setCurModuleId(int value) { + + curModuleId_ = value; + onChanged(); + return this; + } + /** + * uint32 cur_module_id = 8; + * @return This builder for chaining. + */ + public Builder clearCurModuleId() { + + curModuleId_ = 0; + onChanged(); + return this; + } + private long exp_ ; /** * uint64 exp = 10; @@ -1232,8 +1232,8 @@ public final class HomeBasicInfoOuterClass { "\n\023HomeBasicInfo.proto\032\031HomeLimitedShopIn" + "fo.proto\"\330\001\n\rHomeBasicInfo\022\r\n\005level\030\013 \001(" + "\r\022\027\n\017owner_nick_name\030\005 \001(\t\022\027\n\017is_in_edit" + - "_mode\030\t \001(\010\022\025\n\rcur_module_id\030\r \001(\r\022\031\n\021cu" + - "r_room_scene_id\030\010 \001(\r\022\013\n\003exp\030\n \001(\004\022\026\n\016ho" + + "_mode\030\t \001(\010\022\031\n\021cur_room_scene_id\030\r \001(\r\022\025" + + "\n\rcur_module_id\030\010 \001(\r\022\013\n\003exp\030\n \001(\004\022\026\n\016ho" + "me_owner_uid\030\016 \001(\r\022/\n\021limited_shop_info\030" + "\017 \001(\0132\024.HomeLimitedShopInfoB\033\n\031emu.grass" + "cutter.net.protob\006proto3" @@ -1248,7 +1248,7 @@ public final class HomeBasicInfoOuterClass { internal_static_HomeBasicInfo_fieldAccessorTable = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_HomeBasicInfo_descriptor, - new java.lang.String[] { "Level", "OwnerNickName", "IsInEditMode", "CurModuleId", "CurRoomSceneId", "Exp", "HomeOwnerUid", "LimitedShopInfo", }); + new java.lang.String[] { "Level", "OwnerNickName", "IsInEditMode", "CurRoomSceneId", "CurModuleId", "Exp", "HomeOwnerUid", "LimitedShopInfo", }); emu.grasscutter.net.proto.HomeLimitedShopInfoOuterClass.getDescriptor(); } diff --git a/src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopInfoOuterClass.java b/src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopInfoOuterClass.java index d37ebbd11..ca534a10f 100644 --- a/src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopInfoOuterClass.java +++ b/src/generated/main/java/emu/grasscutter/net/proto/HomeLimitedShopInfoOuterClass.java @@ -19,16 +19,16 @@ public final class HomeLimitedShopInfoOuterClass { com.google.protobuf.MessageOrBuilder { /** - * fixed32 PCECKPDEEBD = 13; - * @return The pCECKPDEEBD. + * fixed32 end_time = 13; + * @return The endTime. */ - int getPCECKPDEEBD(); + int getEndTime(); /** - * fixed32 IMBFLHNJAPD = 6; - * @return The iMBFLHNJAPD. + * fixed32 start_time = 6; + * @return The startTime. */ - int getIMBFLHNJAPD(); + int getStartTime(); /** * fixed32 LMJPHDCDAJK = 15; @@ -128,7 +128,7 @@ public final class HomeLimitedShopInfoOuterClass { } case 53: { - iMBFLHNJAPD_ = input.readFixed32(); + startTime_ = input.readFixed32(); break; } case 58: { @@ -159,7 +159,7 @@ public final class HomeLimitedShopInfoOuterClass { } case 109: { - pCECKPDEEBD_ = input.readFixed32(); + endTime_ = input.readFixed32(); break; } case 125: { @@ -199,26 +199,26 @@ public final class HomeLimitedShopInfoOuterClass { emu.grasscutter.net.proto.HomeLimitedShopInfoOuterClass.HomeLimitedShopInfo.class, emu.grasscutter.net.proto.HomeLimitedShopInfoOuterClass.HomeLimitedShopInfo.Builder.class); } - public static final int PCECKPDEEBD_FIELD_NUMBER = 13; - private int pCECKPDEEBD_; + public static final int END_TIME_FIELD_NUMBER = 13; + private int endTime_; /** - * fixed32 PCECKPDEEBD = 13; - * @return The pCECKPDEEBD. + * fixed32 end_time = 13; + * @return The endTime. */ @java.lang.Override - public int getPCECKPDEEBD() { - return pCECKPDEEBD_; + public int getEndTime() { + return endTime_; } - public static final int IMBFLHNJAPD_FIELD_NUMBER = 6; - private int iMBFLHNJAPD_; + public static final int START_TIME_FIELD_NUMBER = 6; + private int startTime_; /** - * fixed32 IMBFLHNJAPD = 6; - * @return The iMBFLHNJAPD. + * fixed32 start_time = 6; + * @return The startTime. */ @java.lang.Override - public int getIMBFLHNJAPD() { - return iMBFLHNJAPD_; + public int getStartTime() { + return startTime_; } public static final int LMJPHDCDAJK_FIELD_NUMBER = 15; @@ -312,8 +312,8 @@ public final class HomeLimitedShopInfoOuterClass { if (uid_ != 0) { output.writeUInt32(2, uid_); } - if (iMBFLHNJAPD_ != 0) { - output.writeFixed32(6, iMBFLHNJAPD_); + if (startTime_ != 0) { + output.writeFixed32(6, startTime_); } if (djinnRot_ != null) { output.writeMessage(7, getDjinnRot()); @@ -321,8 +321,8 @@ public final class HomeLimitedShopInfoOuterClass { if (djinnPos_ != null) { output.writeMessage(8, getDjinnPos()); } - if (pCECKPDEEBD_ != 0) { - output.writeFixed32(13, pCECKPDEEBD_); + if (endTime_ != 0) { + output.writeFixed32(13, endTime_); } if (lMJPHDCDAJK_ != 0) { output.writeFixed32(15, lMJPHDCDAJK_); @@ -340,9 +340,9 @@ public final class HomeLimitedShopInfoOuterClass { size += com.google.protobuf.CodedOutputStream .computeUInt32Size(2, uid_); } - if (iMBFLHNJAPD_ != 0) { + if (startTime_ != 0) { size += com.google.protobuf.CodedOutputStream - .computeFixed32Size(6, iMBFLHNJAPD_); + .computeFixed32Size(6, startTime_); } if (djinnRot_ != null) { size += com.google.protobuf.CodedOutputStream @@ -352,9 +352,9 @@ public final class HomeLimitedShopInfoOuterClass { size += com.google.protobuf.CodedOutputStream .computeMessageSize(8, getDjinnPos()); } - if (pCECKPDEEBD_ != 0) { + if (endTime_ != 0) { size += com.google.protobuf.CodedOutputStream - .computeFixed32Size(13, pCECKPDEEBD_); + .computeFixed32Size(13, endTime_); } if (lMJPHDCDAJK_ != 0) { size += com.google.protobuf.CodedOutputStream @@ -375,10 +375,10 @@ public final class HomeLimitedShopInfoOuterClass { } emu.grasscutter.net.proto.HomeLimitedShopInfoOuterClass.HomeLimitedShopInfo other = (emu.grasscutter.net.proto.HomeLimitedShopInfoOuterClass.HomeLimitedShopInfo) obj; - if (getPCECKPDEEBD() - != other.getPCECKPDEEBD()) return false; - if (getIMBFLHNJAPD() - != other.getIMBFLHNJAPD()) return false; + if (getEndTime() + != other.getEndTime()) return false; + if (getStartTime() + != other.getStartTime()) return false; if (getLMJPHDCDAJK() != other.getLMJPHDCDAJK()) return false; if (hasDjinnRot() != other.hasDjinnRot()) return false; @@ -404,10 +404,10 @@ public final class HomeLimitedShopInfoOuterClass { } int hash = 41; hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + PCECKPDEEBD_FIELD_NUMBER; - hash = (53 * hash) + getPCECKPDEEBD(); - hash = (37 * hash) + IMBFLHNJAPD_FIELD_NUMBER; - hash = (53 * hash) + getIMBFLHNJAPD(); + hash = (37 * hash) + END_TIME_FIELD_NUMBER; + hash = (53 * hash) + getEndTime(); + hash = (37 * hash) + START_TIME_FIELD_NUMBER; + hash = (53 * hash) + getStartTime(); hash = (37 * hash) + LMJPHDCDAJK_FIELD_NUMBER; hash = (53 * hash) + getLMJPHDCDAJK(); if (hasDjinnRot()) { @@ -557,9 +557,9 @@ public final class HomeLimitedShopInfoOuterClass { @java.lang.Override public Builder clear() { super.clear(); - pCECKPDEEBD_ = 0; + endTime_ = 0; - iMBFLHNJAPD_ = 0; + startTime_ = 0; lMJPHDCDAJK_ = 0; @@ -603,8 +603,8 @@ public final class HomeLimitedShopInfoOuterClass { @java.lang.Override public emu.grasscutter.net.proto.HomeLimitedShopInfoOuterClass.HomeLimitedShopInfo buildPartial() { emu.grasscutter.net.proto.HomeLimitedShopInfoOuterClass.HomeLimitedShopInfo result = new emu.grasscutter.net.proto.HomeLimitedShopInfoOuterClass.HomeLimitedShopInfo(this); - result.pCECKPDEEBD_ = pCECKPDEEBD_; - result.iMBFLHNJAPD_ = iMBFLHNJAPD_; + result.endTime_ = endTime_; + result.startTime_ = startTime_; result.lMJPHDCDAJK_ = lMJPHDCDAJK_; if (djinnRotBuilder_ == null) { result.djinnRot_ = djinnRot_; @@ -665,11 +665,11 @@ public final class HomeLimitedShopInfoOuterClass { public Builder mergeFrom(emu.grasscutter.net.proto.HomeLimitedShopInfoOuterClass.HomeLimitedShopInfo other) { if (other == emu.grasscutter.net.proto.HomeLimitedShopInfoOuterClass.HomeLimitedShopInfo.getDefaultInstance()) return this; - if (other.getPCECKPDEEBD() != 0) { - setPCECKPDEEBD(other.getPCECKPDEEBD()); + if (other.getEndTime() != 0) { + setEndTime(other.getEndTime()); } - if (other.getIMBFLHNJAPD() != 0) { - setIMBFLHNJAPD(other.getIMBFLHNJAPD()); + if (other.getStartTime() != 0) { + setStartTime(other.getStartTime()); } if (other.getLMJPHDCDAJK() != 0) { setLMJPHDCDAJK(other.getLMJPHDCDAJK()); @@ -712,64 +712,64 @@ public final class HomeLimitedShopInfoOuterClass { return this; } - private int pCECKPDEEBD_ ; + private int endTime_ ; /** - * fixed32 PCECKPDEEBD = 13; - * @return The pCECKPDEEBD. + * fixed32 end_time = 13; + * @return The endTime. */ @java.lang.Override - public int getPCECKPDEEBD() { - return pCECKPDEEBD_; + public int getEndTime() { + return endTime_; } /** - * fixed32 PCECKPDEEBD = 13; - * @param value The pCECKPDEEBD to set. + * fixed32 end_time = 13; + * @param value The endTime to set. * @return This builder for chaining. */ - public Builder setPCECKPDEEBD(int value) { + public Builder setEndTime(int value) { - pCECKPDEEBD_ = value; + endTime_ = value; onChanged(); return this; } /** - * fixed32 PCECKPDEEBD = 13; + * fixed32 end_time = 13; * @return This builder for chaining. */ - public Builder clearPCECKPDEEBD() { + public Builder clearEndTime() { - pCECKPDEEBD_ = 0; + endTime_ = 0; onChanged(); return this; } - private int iMBFLHNJAPD_ ; + private int startTime_ ; /** - * fixed32 IMBFLHNJAPD = 6; - * @return The iMBFLHNJAPD. + * fixed32 start_time = 6; + * @return The startTime. */ @java.lang.Override - public int getIMBFLHNJAPD() { - return iMBFLHNJAPD_; + public int getStartTime() { + return startTime_; } /** - * fixed32 IMBFLHNJAPD = 6; - * @param value The iMBFLHNJAPD to set. + * fixed32 start_time = 6; + * @param value The startTime to set. * @return This builder for chaining. */ - public Builder setIMBFLHNJAPD(int value) { + public Builder setStartTime(int value) { - iMBFLHNJAPD_ = value; + startTime_ = value; onChanged(); return this; } /** - * fixed32 IMBFLHNJAPD = 6; + * fixed32 start_time = 6; * @return This builder for chaining. */ - public Builder clearIMBFLHNJAPD() { + public Builder clearStartTime() { - iMBFLHNJAPD_ = 0; + startTime_ = 0; onChanged(); return this; } @@ -1141,11 +1141,11 @@ public final class HomeLimitedShopInfoOuterClass { static { java.lang.String[] descriptorData = { "\n\031HomeLimitedShopInfo.proto\032\014Vector.prot" + - "o\"\231\001\n\023HomeLimitedShopInfo\022\023\n\013PCECKPDEEBD" + - "\030\r \001(\007\022\023\n\013IMBFLHNJAPD\030\006 \001(\007\022\023\n\013LMJPHDCDA" + - "JK\030\017 \001(\007\022\032\n\tdjinn_rot\030\007 \001(\0132\007.Vector\022\032\n\t" + - "djinn_pos\030\010 \001(\0132\007.Vector\022\013\n\003uid\030\002 \001(\rB\033\n" + - "\031emu.grasscutter.net.protob\006proto3" + "o\"\225\001\n\023HomeLimitedShopInfo\022\020\n\010end_time\030\r " + + "\001(\007\022\022\n\nstart_time\030\006 \001(\007\022\023\n\013LMJPHDCDAJK\030\017" + + " \001(\007\022\032\n\tdjinn_rot\030\007 \001(\0132\007.Vector\022\032\n\tdjin" + + "n_pos\030\010 \001(\0132\007.Vector\022\013\n\003uid\030\002 \001(\rB\033\n\031emu" + + ".grasscutter.net.protob\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, @@ -1157,7 +1157,7 @@ public final class HomeLimitedShopInfoOuterClass { internal_static_HomeLimitedShopInfo_fieldAccessorTable = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_HomeLimitedShopInfo_descriptor, - new java.lang.String[] { "PCECKPDEEBD", "IMBFLHNJAPD", "LMJPHDCDAJK", "DjinnRot", "DjinnPos", "Uid", }); + new java.lang.String[] { "EndTime", "StartTime", "LMJPHDCDAJK", "DjinnRot", "DjinnPos", "Uid", }); emu.grasscutter.net.proto.VectorOuterClass.getDescriptor(); } diff --git a/src/generated/main/java/emu/grasscutter/net/proto/HomeMarkPointSceneDataOuterClass.java b/src/generated/main/java/emu/grasscutter/net/proto/HomeMarkPointSceneDataOuterClass.java index 0903ed7bb..0635f01f0 100644 --- a/src/generated/main/java/emu/grasscutter/net/proto/HomeMarkPointSceneDataOuterClass.java +++ b/src/generated/main/java/emu/grasscutter/net/proto/HomeMarkPointSceneDataOuterClass.java @@ -43,19 +43,19 @@ public final class HomeMarkPointSceneDataOuterClass { int index); /** - * .Vector teapot_spirit_pos = 8; - * @return Whether the teapotSpiritPos field is set. + * .Vector safe_point_pos = 8; + * @return Whether the safePointPos field is set. */ - boolean hasTeapotSpiritPos(); + boolean hasSafePointPos(); /** - * .Vector teapot_spirit_pos = 8; - * @return The teapotSpiritPos. + * .Vector safe_point_pos = 8; + * @return The safePointPos. */ - emu.grasscutter.net.proto.VectorOuterClass.Vector getTeapotSpiritPos(); + emu.grasscutter.net.proto.VectorOuterClass.Vector getSafePointPos(); /** - * .Vector teapot_spirit_pos = 8; + * .Vector safe_point_pos = 8; */ - emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getTeapotSpiritPosOrBuilder(); + emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getSafePointPosOrBuilder(); /** * uint32 module_id = 9; @@ -70,19 +70,19 @@ public final class HomeMarkPointSceneDataOuterClass { int getSceneId(); /** - * .Vector safe_point_pos = 3; - * @return Whether the safePointPos field is set. + * .Vector teapot_spirit_pos = 3; + * @return Whether the teapotSpiritPos field is set. */ - boolean hasSafePointPos(); + boolean hasTeapotSpiritPos(); /** - * .Vector safe_point_pos = 3; - * @return The safePointPos. + * .Vector teapot_spirit_pos = 3; + * @return The teapotSpiritPos. */ - emu.grasscutter.net.proto.VectorOuterClass.Vector getSafePointPos(); + emu.grasscutter.net.proto.VectorOuterClass.Vector getTeapotSpiritPos(); /** - * .Vector safe_point_pos = 3; + * .Vector teapot_spirit_pos = 3; */ - emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getSafePointPosOrBuilder(); + emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getTeapotSpiritPosOrBuilder(); } /** *
@@ -137,13 +137,13 @@ public final class HomeMarkPointSceneDataOuterClass {
               break;
             case 26: {
               emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder subBuilder = null;
-              if (safePointPos_ != null) {
-                subBuilder = safePointPos_.toBuilder();
+              if (teapotSpiritPos_ != null) {
+                subBuilder = teapotSpiritPos_.toBuilder();
               }
-              safePointPos_ = input.readMessage(emu.grasscutter.net.proto.VectorOuterClass.Vector.parser(), extensionRegistry);
+              teapotSpiritPos_ = input.readMessage(emu.grasscutter.net.proto.VectorOuterClass.Vector.parser(), extensionRegistry);
               if (subBuilder != null) {
-                subBuilder.mergeFrom(safePointPos_);
-                safePointPos_ = subBuilder.buildPartial();
+                subBuilder.mergeFrom(teapotSpiritPos_);
+                teapotSpiritPos_ = subBuilder.buildPartial();
               }
 
               break;
@@ -164,13 +164,13 @@ public final class HomeMarkPointSceneDataOuterClass {
             }
             case 66: {
               emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder subBuilder = null;
-              if (teapotSpiritPos_ != null) {
-                subBuilder = teapotSpiritPos_.toBuilder();
+              if (safePointPos_ != null) {
+                subBuilder = safePointPos_.toBuilder();
               }
-              teapotSpiritPos_ = input.readMessage(emu.grasscutter.net.proto.VectorOuterClass.Vector.parser(), extensionRegistry);
+              safePointPos_ = input.readMessage(emu.grasscutter.net.proto.VectorOuterClass.Vector.parser(), extensionRegistry);
               if (subBuilder != null) {
-                subBuilder.mergeFrom(teapotSpiritPos_);
-                teapotSpiritPos_ = subBuilder.buildPartial();
+                subBuilder.mergeFrom(safePointPos_);
+                safePointPos_ = subBuilder.buildPartial();
               }
 
               break;
@@ -255,30 +255,30 @@ public final class HomeMarkPointSceneDataOuterClass {
       return furnitureList_.get(index);
     }
 
-    public static final int TEAPOT_SPIRIT_POS_FIELD_NUMBER = 8;
-    private emu.grasscutter.net.proto.VectorOuterClass.Vector teapotSpiritPos_;
+    public static final int SAFE_POINT_POS_FIELD_NUMBER = 8;
+    private emu.grasscutter.net.proto.VectorOuterClass.Vector safePointPos_;
     /**
-     * .Vector teapot_spirit_pos = 8;
-     * @return Whether the teapotSpiritPos field is set.
+     * .Vector safe_point_pos = 8;
+     * @return Whether the safePointPos field is set.
      */
     @java.lang.Override
-    public boolean hasTeapotSpiritPos() {
-      return teapotSpiritPos_ != null;
+    public boolean hasSafePointPos() {
+      return safePointPos_ != null;
     }
     /**
-     * .Vector teapot_spirit_pos = 8;
-     * @return The teapotSpiritPos.
+     * .Vector safe_point_pos = 8;
+     * @return The safePointPos.
      */
     @java.lang.Override
-    public emu.grasscutter.net.proto.VectorOuterClass.Vector getTeapotSpiritPos() {
-      return teapotSpiritPos_ == null ? emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : teapotSpiritPos_;
+    public emu.grasscutter.net.proto.VectorOuterClass.Vector getSafePointPos() {
+      return safePointPos_ == null ? emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : safePointPos_;
     }
     /**
-     * .Vector teapot_spirit_pos = 8;
+     * .Vector safe_point_pos = 8;
      */
     @java.lang.Override
-    public emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getTeapotSpiritPosOrBuilder() {
-      return getTeapotSpiritPos();
+    public emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getSafePointPosOrBuilder() {
+      return getSafePointPos();
     }
 
     public static final int MODULE_ID_FIELD_NUMBER = 9;
@@ -303,30 +303,30 @@ public final class HomeMarkPointSceneDataOuterClass {
       return sceneId_;
     }
 
-    public static final int SAFE_POINT_POS_FIELD_NUMBER = 3;
-    private emu.grasscutter.net.proto.VectorOuterClass.Vector safePointPos_;
+    public static final int TEAPOT_SPIRIT_POS_FIELD_NUMBER = 3;
+    private emu.grasscutter.net.proto.VectorOuterClass.Vector teapotSpiritPos_;
     /**
-     * .Vector safe_point_pos = 3;
-     * @return Whether the safePointPos field is set.
+     * .Vector teapot_spirit_pos = 3;
+     * @return Whether the teapotSpiritPos field is set.
      */
     @java.lang.Override
-    public boolean hasSafePointPos() {
-      return safePointPos_ != null;
+    public boolean hasTeapotSpiritPos() {
+      return teapotSpiritPos_ != null;
     }
     /**
-     * .Vector safe_point_pos = 3;
-     * @return The safePointPos.
+     * .Vector teapot_spirit_pos = 3;
+     * @return The teapotSpiritPos.
      */
     @java.lang.Override
-    public emu.grasscutter.net.proto.VectorOuterClass.Vector getSafePointPos() {
-      return safePointPos_ == null ? emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : safePointPos_;
+    public emu.grasscutter.net.proto.VectorOuterClass.Vector getTeapotSpiritPos() {
+      return teapotSpiritPos_ == null ? emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : teapotSpiritPos_;
     }
     /**
-     * .Vector safe_point_pos = 3;
+     * .Vector teapot_spirit_pos = 3;
      */
     @java.lang.Override
-    public emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getSafePointPosOrBuilder() {
-      return getSafePointPos();
+    public emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getTeapotSpiritPosOrBuilder() {
+      return getTeapotSpiritPos();
     }
 
     private byte memoizedIsInitialized = -1;
@@ -343,8 +343,8 @@ public final class HomeMarkPointSceneDataOuterClass {
     @java.lang.Override
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
-      if (safePointPos_ != null) {
-        output.writeMessage(3, getSafePointPos());
+      if (teapotSpiritPos_ != null) {
+        output.writeMessage(3, getTeapotSpiritPos());
       }
       if (sceneId_ != 0) {
         output.writeUInt32(5, sceneId_);
@@ -352,8 +352,8 @@ public final class HomeMarkPointSceneDataOuterClass {
       for (int i = 0; i < furnitureList_.size(); i++) {
         output.writeMessage(7, furnitureList_.get(i));
       }
-      if (teapotSpiritPos_ != null) {
-        output.writeMessage(8, getTeapotSpiritPos());
+      if (safePointPos_ != null) {
+        output.writeMessage(8, getSafePointPos());
       }
       if (moduleId_ != 0) {
         output.writeUInt32(9, moduleId_);
@@ -367,9 +367,9 @@ public final class HomeMarkPointSceneDataOuterClass {
       if (size != -1) return size;
 
       size = 0;
-      if (safePointPos_ != null) {
+      if (teapotSpiritPos_ != null) {
         size += com.google.protobuf.CodedOutputStream
-          .computeMessageSize(3, getSafePointPos());
+          .computeMessageSize(3, getTeapotSpiritPos());
       }
       if (sceneId_ != 0) {
         size += com.google.protobuf.CodedOutputStream
@@ -379,9 +379,9 @@ public final class HomeMarkPointSceneDataOuterClass {
         size += com.google.protobuf.CodedOutputStream
           .computeMessageSize(7, furnitureList_.get(i));
       }
-      if (teapotSpiritPos_ != null) {
+      if (safePointPos_ != null) {
         size += com.google.protobuf.CodedOutputStream
-          .computeMessageSize(8, getTeapotSpiritPos());
+          .computeMessageSize(8, getSafePointPos());
       }
       if (moduleId_ != 0) {
         size += com.google.protobuf.CodedOutputStream
@@ -404,19 +404,19 @@ public final class HomeMarkPointSceneDataOuterClass {
 
       if (!getFurnitureListList()
           .equals(other.getFurnitureListList())) return false;
-      if (hasTeapotSpiritPos() != other.hasTeapotSpiritPos()) return false;
-      if (hasTeapotSpiritPos()) {
-        if (!getTeapotSpiritPos()
-            .equals(other.getTeapotSpiritPos())) return false;
+      if (hasSafePointPos() != other.hasSafePointPos()) return false;
+      if (hasSafePointPos()) {
+        if (!getSafePointPos()
+            .equals(other.getSafePointPos())) return false;
       }
       if (getModuleId()
           != other.getModuleId()) return false;
       if (getSceneId()
           != other.getSceneId()) return false;
-      if (hasSafePointPos() != other.hasSafePointPos()) return false;
-      if (hasSafePointPos()) {
-        if (!getSafePointPos()
-            .equals(other.getSafePointPos())) return false;
+      if (hasTeapotSpiritPos() != other.hasTeapotSpiritPos()) return false;
+      if (hasTeapotSpiritPos()) {
+        if (!getTeapotSpiritPos()
+            .equals(other.getTeapotSpiritPos())) return false;
       }
       if (!unknownFields.equals(other.unknownFields)) return false;
       return true;
@@ -433,17 +433,17 @@ public final class HomeMarkPointSceneDataOuterClass {
         hash = (37 * hash) + FURNITURE_LIST_FIELD_NUMBER;
         hash = (53 * hash) + getFurnitureListList().hashCode();
       }
-      if (hasTeapotSpiritPos()) {
-        hash = (37 * hash) + TEAPOT_SPIRIT_POS_FIELD_NUMBER;
-        hash = (53 * hash) + getTeapotSpiritPos().hashCode();
+      if (hasSafePointPos()) {
+        hash = (37 * hash) + SAFE_POINT_POS_FIELD_NUMBER;
+        hash = (53 * hash) + getSafePointPos().hashCode();
       }
       hash = (37 * hash) + MODULE_ID_FIELD_NUMBER;
       hash = (53 * hash) + getModuleId();
       hash = (37 * hash) + SCENE_ID_FIELD_NUMBER;
       hash = (53 * hash) + getSceneId();
-      if (hasSafePointPos()) {
-        hash = (37 * hash) + SAFE_POINT_POS_FIELD_NUMBER;
-        hash = (53 * hash) + getSafePointPos().hashCode();
+      if (hasTeapotSpiritPos()) {
+        hash = (37 * hash) + TEAPOT_SPIRIT_POS_FIELD_NUMBER;
+        hash = (53 * hash) + getTeapotSpiritPos().hashCode();
       }
       hash = (29 * hash) + unknownFields.hashCode();
       memoizedHashCode = hash;
@@ -589,22 +589,22 @@ public final class HomeMarkPointSceneDataOuterClass {
         } else {
           furnitureListBuilder_.clear();
         }
-        if (teapotSpiritPosBuilder_ == null) {
-          teapotSpiritPos_ = null;
-        } else {
-          teapotSpiritPos_ = null;
-          teapotSpiritPosBuilder_ = null;
-        }
-        moduleId_ = 0;
-
-        sceneId_ = 0;
-
         if (safePointPosBuilder_ == null) {
           safePointPos_ = null;
         } else {
           safePointPos_ = null;
           safePointPosBuilder_ = null;
         }
+        moduleId_ = 0;
+
+        sceneId_ = 0;
+
+        if (teapotSpiritPosBuilder_ == null) {
+          teapotSpiritPos_ = null;
+        } else {
+          teapotSpiritPos_ = null;
+          teapotSpiritPosBuilder_ = null;
+        }
         return this;
       }
 
@@ -641,18 +641,18 @@ public final class HomeMarkPointSceneDataOuterClass {
         } else {
           result.furnitureList_ = furnitureListBuilder_.build();
         }
-        if (teapotSpiritPosBuilder_ == null) {
-          result.teapotSpiritPos_ = teapotSpiritPos_;
-        } else {
-          result.teapotSpiritPos_ = teapotSpiritPosBuilder_.build();
-        }
-        result.moduleId_ = moduleId_;
-        result.sceneId_ = sceneId_;
         if (safePointPosBuilder_ == null) {
           result.safePointPos_ = safePointPos_;
         } else {
           result.safePointPos_ = safePointPosBuilder_.build();
         }
+        result.moduleId_ = moduleId_;
+        result.sceneId_ = sceneId_;
+        if (teapotSpiritPosBuilder_ == null) {
+          result.teapotSpiritPos_ = teapotSpiritPos_;
+        } else {
+          result.teapotSpiritPos_ = teapotSpiritPosBuilder_.build();
+        }
         onBuilt();
         return result;
       }
@@ -727,8 +727,8 @@ public final class HomeMarkPointSceneDataOuterClass {
             }
           }
         }
-        if (other.hasTeapotSpiritPos()) {
-          mergeTeapotSpiritPos(other.getTeapotSpiritPos());
+        if (other.hasSafePointPos()) {
+          mergeSafePointPos(other.getSafePointPos());
         }
         if (other.getModuleId() != 0) {
           setModuleId(other.getModuleId());
@@ -736,8 +736,8 @@ public final class HomeMarkPointSceneDataOuterClass {
         if (other.getSceneId() != 0) {
           setSceneId(other.getSceneId());
         }
-        if (other.hasSafePointPos()) {
-          mergeSafePointPos(other.getSafePointPos());
+        if (other.hasTeapotSpiritPos()) {
+          mergeTeapotSpiritPos(other.getTeapotSpiritPos());
         }
         this.mergeUnknownFields(other.unknownFields);
         onChanged();
@@ -1009,123 +1009,123 @@ public final class HomeMarkPointSceneDataOuterClass {
         return furnitureListBuilder_;
       }
 
-      private emu.grasscutter.net.proto.VectorOuterClass.Vector teapotSpiritPos_;
+      private emu.grasscutter.net.proto.VectorOuterClass.Vector safePointPos_;
       private com.google.protobuf.SingleFieldBuilderV3<
-          emu.grasscutter.net.proto.VectorOuterClass.Vector, emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder, emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder> teapotSpiritPosBuilder_;
+          emu.grasscutter.net.proto.VectorOuterClass.Vector, emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder, emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder> safePointPosBuilder_;
       /**
-       * .Vector teapot_spirit_pos = 8;
-       * @return Whether the teapotSpiritPos field is set.
+       * .Vector safe_point_pos = 8;
+       * @return Whether the safePointPos field is set.
        */
-      public boolean hasTeapotSpiritPos() {
-        return teapotSpiritPosBuilder_ != null || teapotSpiritPos_ != null;
+      public boolean hasSafePointPos() {
+        return safePointPosBuilder_ != null || safePointPos_ != null;
       }
       /**
-       * .Vector teapot_spirit_pos = 8;
-       * @return The teapotSpiritPos.
+       * .Vector safe_point_pos = 8;
+       * @return The safePointPos.
        */
-      public emu.grasscutter.net.proto.VectorOuterClass.Vector getTeapotSpiritPos() {
-        if (teapotSpiritPosBuilder_ == null) {
-          return teapotSpiritPos_ == null ? emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : teapotSpiritPos_;
+      public emu.grasscutter.net.proto.VectorOuterClass.Vector getSafePointPos() {
+        if (safePointPosBuilder_ == null) {
+          return safePointPos_ == null ? emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : safePointPos_;
         } else {
-          return teapotSpiritPosBuilder_.getMessage();
+          return safePointPosBuilder_.getMessage();
         }
       }
       /**
-       * .Vector teapot_spirit_pos = 8;
+       * .Vector safe_point_pos = 8;
        */
-      public Builder setTeapotSpiritPos(emu.grasscutter.net.proto.VectorOuterClass.Vector value) {
-        if (teapotSpiritPosBuilder_ == null) {
+      public Builder setSafePointPos(emu.grasscutter.net.proto.VectorOuterClass.Vector value) {
+        if (safePointPosBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
           }
-          teapotSpiritPos_ = value;
+          safePointPos_ = value;
           onChanged();
         } else {
-          teapotSpiritPosBuilder_.setMessage(value);
+          safePointPosBuilder_.setMessage(value);
         }
 
         return this;
       }
       /**
-       * .Vector teapot_spirit_pos = 8;
+       * .Vector safe_point_pos = 8;
        */
-      public Builder setTeapotSpiritPos(
+      public Builder setSafePointPos(
           emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder builderForValue) {
-        if (teapotSpiritPosBuilder_ == null) {
-          teapotSpiritPos_ = builderForValue.build();
+        if (safePointPosBuilder_ == null) {
+          safePointPos_ = builderForValue.build();
           onChanged();
         } else {
-          teapotSpiritPosBuilder_.setMessage(builderForValue.build());
+          safePointPosBuilder_.setMessage(builderForValue.build());
         }
 
         return this;
       }
       /**
-       * .Vector teapot_spirit_pos = 8;
+       * .Vector safe_point_pos = 8;
        */
-      public Builder mergeTeapotSpiritPos(emu.grasscutter.net.proto.VectorOuterClass.Vector value) {
-        if (teapotSpiritPosBuilder_ == null) {
-          if (teapotSpiritPos_ != null) {
-            teapotSpiritPos_ =
-              emu.grasscutter.net.proto.VectorOuterClass.Vector.newBuilder(teapotSpiritPos_).mergeFrom(value).buildPartial();
+      public Builder mergeSafePointPos(emu.grasscutter.net.proto.VectorOuterClass.Vector value) {
+        if (safePointPosBuilder_ == null) {
+          if (safePointPos_ != null) {
+            safePointPos_ =
+              emu.grasscutter.net.proto.VectorOuterClass.Vector.newBuilder(safePointPos_).mergeFrom(value).buildPartial();
           } else {
-            teapotSpiritPos_ = value;
+            safePointPos_ = value;
           }
           onChanged();
         } else {
-          teapotSpiritPosBuilder_.mergeFrom(value);
+          safePointPosBuilder_.mergeFrom(value);
         }
 
         return this;
       }
       /**
-       * .Vector teapot_spirit_pos = 8;
+       * .Vector safe_point_pos = 8;
        */
-      public Builder clearTeapotSpiritPos() {
-        if (teapotSpiritPosBuilder_ == null) {
-          teapotSpiritPos_ = null;
+      public Builder clearSafePointPos() {
+        if (safePointPosBuilder_ == null) {
+          safePointPos_ = null;
           onChanged();
         } else {
-          teapotSpiritPos_ = null;
-          teapotSpiritPosBuilder_ = null;
+          safePointPos_ = null;
+          safePointPosBuilder_ = null;
         }
 
         return this;
       }
       /**
-       * .Vector teapot_spirit_pos = 8;
+       * .Vector safe_point_pos = 8;
        */
-      public emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder getTeapotSpiritPosBuilder() {
+      public emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder getSafePointPosBuilder() {
         
         onChanged();
-        return getTeapotSpiritPosFieldBuilder().getBuilder();
+        return getSafePointPosFieldBuilder().getBuilder();
       }
       /**
-       * .Vector teapot_spirit_pos = 8;
+       * .Vector safe_point_pos = 8;
        */
-      public emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getTeapotSpiritPosOrBuilder() {
-        if (teapotSpiritPosBuilder_ != null) {
-          return teapotSpiritPosBuilder_.getMessageOrBuilder();
+      public emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getSafePointPosOrBuilder() {
+        if (safePointPosBuilder_ != null) {
+          return safePointPosBuilder_.getMessageOrBuilder();
         } else {
-          return teapotSpiritPos_ == null ?
-              emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : teapotSpiritPos_;
+          return safePointPos_ == null ?
+              emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : safePointPos_;
         }
       }
       /**
-       * .Vector teapot_spirit_pos = 8;
+       * .Vector safe_point_pos = 8;
        */
       private com.google.protobuf.SingleFieldBuilderV3<
           emu.grasscutter.net.proto.VectorOuterClass.Vector, emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder, emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder> 
-          getTeapotSpiritPosFieldBuilder() {
-        if (teapotSpiritPosBuilder_ == null) {
-          teapotSpiritPosBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<
+          getSafePointPosFieldBuilder() {
+        if (safePointPosBuilder_ == null) {
+          safePointPosBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<
               emu.grasscutter.net.proto.VectorOuterClass.Vector, emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder, emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder>(
-                  getTeapotSpiritPos(),
+                  getSafePointPos(),
                   getParentForChildren(),
                   isClean());
-          teapotSpiritPos_ = null;
+          safePointPos_ = null;
         }
-        return teapotSpiritPosBuilder_;
+        return safePointPosBuilder_;
       }
 
       private int moduleId_ ;
@@ -1190,123 +1190,123 @@ public final class HomeMarkPointSceneDataOuterClass {
         return this;
       }
 
-      private emu.grasscutter.net.proto.VectorOuterClass.Vector safePointPos_;
+      private emu.grasscutter.net.proto.VectorOuterClass.Vector teapotSpiritPos_;
       private com.google.protobuf.SingleFieldBuilderV3<
-          emu.grasscutter.net.proto.VectorOuterClass.Vector, emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder, emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder> safePointPosBuilder_;
+          emu.grasscutter.net.proto.VectorOuterClass.Vector, emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder, emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder> teapotSpiritPosBuilder_;
       /**
-       * .Vector safe_point_pos = 3;
-       * @return Whether the safePointPos field is set.
+       * .Vector teapot_spirit_pos = 3;
+       * @return Whether the teapotSpiritPos field is set.
        */
-      public boolean hasSafePointPos() {
-        return safePointPosBuilder_ != null || safePointPos_ != null;
+      public boolean hasTeapotSpiritPos() {
+        return teapotSpiritPosBuilder_ != null || teapotSpiritPos_ != null;
       }
       /**
-       * .Vector safe_point_pos = 3;
-       * @return The safePointPos.
+       * .Vector teapot_spirit_pos = 3;
+       * @return The teapotSpiritPos.
        */
-      public emu.grasscutter.net.proto.VectorOuterClass.Vector getSafePointPos() {
-        if (safePointPosBuilder_ == null) {
-          return safePointPos_ == null ? emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : safePointPos_;
+      public emu.grasscutter.net.proto.VectorOuterClass.Vector getTeapotSpiritPos() {
+        if (teapotSpiritPosBuilder_ == null) {
+          return teapotSpiritPos_ == null ? emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : teapotSpiritPos_;
         } else {
-          return safePointPosBuilder_.getMessage();
+          return teapotSpiritPosBuilder_.getMessage();
         }
       }
       /**
-       * .Vector safe_point_pos = 3;
+       * .Vector teapot_spirit_pos = 3;
        */
-      public Builder setSafePointPos(emu.grasscutter.net.proto.VectorOuterClass.Vector value) {
-        if (safePointPosBuilder_ == null) {
+      public Builder setTeapotSpiritPos(emu.grasscutter.net.proto.VectorOuterClass.Vector value) {
+        if (teapotSpiritPosBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
           }
-          safePointPos_ = value;
+          teapotSpiritPos_ = value;
           onChanged();
         } else {
-          safePointPosBuilder_.setMessage(value);
+          teapotSpiritPosBuilder_.setMessage(value);
         }
 
         return this;
       }
       /**
-       * .Vector safe_point_pos = 3;
+       * .Vector teapot_spirit_pos = 3;
        */
-      public Builder setSafePointPos(
+      public Builder setTeapotSpiritPos(
           emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder builderForValue) {
-        if (safePointPosBuilder_ == null) {
-          safePointPos_ = builderForValue.build();
+        if (teapotSpiritPosBuilder_ == null) {
+          teapotSpiritPos_ = builderForValue.build();
           onChanged();
         } else {
-          safePointPosBuilder_.setMessage(builderForValue.build());
+          teapotSpiritPosBuilder_.setMessage(builderForValue.build());
         }
 
         return this;
       }
       /**
-       * .Vector safe_point_pos = 3;
+       * .Vector teapot_spirit_pos = 3;
        */
-      public Builder mergeSafePointPos(emu.grasscutter.net.proto.VectorOuterClass.Vector value) {
-        if (safePointPosBuilder_ == null) {
-          if (safePointPos_ != null) {
-            safePointPos_ =
-              emu.grasscutter.net.proto.VectorOuterClass.Vector.newBuilder(safePointPos_).mergeFrom(value).buildPartial();
+      public Builder mergeTeapotSpiritPos(emu.grasscutter.net.proto.VectorOuterClass.Vector value) {
+        if (teapotSpiritPosBuilder_ == null) {
+          if (teapotSpiritPos_ != null) {
+            teapotSpiritPos_ =
+              emu.grasscutter.net.proto.VectorOuterClass.Vector.newBuilder(teapotSpiritPos_).mergeFrom(value).buildPartial();
           } else {
-            safePointPos_ = value;
+            teapotSpiritPos_ = value;
           }
           onChanged();
         } else {
-          safePointPosBuilder_.mergeFrom(value);
+          teapotSpiritPosBuilder_.mergeFrom(value);
         }
 
         return this;
       }
       /**
-       * .Vector safe_point_pos = 3;
+       * .Vector teapot_spirit_pos = 3;
        */
-      public Builder clearSafePointPos() {
-        if (safePointPosBuilder_ == null) {
-          safePointPos_ = null;
+      public Builder clearTeapotSpiritPos() {
+        if (teapotSpiritPosBuilder_ == null) {
+          teapotSpiritPos_ = null;
           onChanged();
         } else {
-          safePointPos_ = null;
-          safePointPosBuilder_ = null;
+          teapotSpiritPos_ = null;
+          teapotSpiritPosBuilder_ = null;
         }
 
         return this;
       }
       /**
-       * .Vector safe_point_pos = 3;
+       * .Vector teapot_spirit_pos = 3;
        */
-      public emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder getSafePointPosBuilder() {
+      public emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder getTeapotSpiritPosBuilder() {
         
         onChanged();
-        return getSafePointPosFieldBuilder().getBuilder();
+        return getTeapotSpiritPosFieldBuilder().getBuilder();
       }
       /**
-       * .Vector safe_point_pos = 3;
+       * .Vector teapot_spirit_pos = 3;
        */
-      public emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getSafePointPosOrBuilder() {
-        if (safePointPosBuilder_ != null) {
-          return safePointPosBuilder_.getMessageOrBuilder();
+      public emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder getTeapotSpiritPosOrBuilder() {
+        if (teapotSpiritPosBuilder_ != null) {
+          return teapotSpiritPosBuilder_.getMessageOrBuilder();
         } else {
-          return safePointPos_ == null ?
-              emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : safePointPos_;
+          return teapotSpiritPos_ == null ?
+              emu.grasscutter.net.proto.VectorOuterClass.Vector.getDefaultInstance() : teapotSpiritPos_;
         }
       }
       /**
-       * .Vector safe_point_pos = 3;
+       * .Vector teapot_spirit_pos = 3;
        */
       private com.google.protobuf.SingleFieldBuilderV3<
           emu.grasscutter.net.proto.VectorOuterClass.Vector, emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder, emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder> 
-          getSafePointPosFieldBuilder() {
-        if (safePointPosBuilder_ == null) {
-          safePointPosBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<
+          getTeapotSpiritPosFieldBuilder() {
+        if (teapotSpiritPosBuilder_ == null) {
+          teapotSpiritPosBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<
               emu.grasscutter.net.proto.VectorOuterClass.Vector, emu.grasscutter.net.proto.VectorOuterClass.Vector.Builder, emu.grasscutter.net.proto.VectorOuterClass.VectorOrBuilder>(
-                  getSafePointPos(),
+                  getTeapotSpiritPos(),
                   getParentForChildren(),
                   isClean());
-          safePointPos_ = null;
+          teapotSpiritPos_ = null;
         }
-        return safePointPosBuilder_;
+        return teapotSpiritPosBuilder_;
       }
       @java.lang.Override
       public final Builder setUnknownFields(
@@ -1378,10 +1378,10 @@ public final class HomeMarkPointSceneDataOuterClass {
       "\n\034HomeMarkPointSceneData.proto\032 HomeMark" +
       "PointFurnitureData.proto\032\014Vector.proto\"\267" +
       "\001\n\026HomeMarkPointSceneData\0223\n\016furniture_l" +
-      "ist\030\007 \003(\0132\033.HomeMarkPointFurnitureData\022\"" +
-      "\n\021teapot_spirit_pos\030\010 \001(\0132\007.Vector\022\021\n\tmo" +
-      "dule_id\030\t \001(\r\022\020\n\010scene_id\030\005 \001(\r\022\037\n\016safe_" +
-      "point_pos\030\003 \001(\0132\007.VectorB\033\n\031emu.grasscut" +
+      "ist\030\007 \003(\0132\033.HomeMarkPointFurnitureData\022\037" +
+      "\n\016safe_point_pos\030\010 \001(\0132\007.Vector\022\021\n\tmodul" +
+      "e_id\030\t \001(\r\022\020\n\010scene_id\030\005 \001(\r\022\"\n\021teapot_s" +
+      "pirit_pos\030\003 \001(\0132\007.VectorB\033\n\031emu.grasscut" +
       "ter.net.protob\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
@@ -1395,7 +1395,7 @@ public final class HomeMarkPointSceneDataOuterClass {
     internal_static_HomeMarkPointSceneData_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_HomeMarkPointSceneData_descriptor,
-        new java.lang.String[] { "FurnitureList", "TeapotSpiritPos", "ModuleId", "SceneId", "SafePointPos", });
+        new java.lang.String[] { "FurnitureList", "SafePointPos", "ModuleId", "SceneId", "TeapotSpiritPos", });
     emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass.getDescriptor();
     emu.grasscutter.net.proto.VectorOuterClass.getDescriptor();
   }
diff --git a/src/generated/main/java/emu/grasscutter/net/proto/PlayerHomeCompInfoOuterClass.java b/src/generated/main/java/emu/grasscutter/net/proto/PlayerHomeCompInfoOuterClass.java
index 0d58d4e72..0cb83da39 100644
--- a/src/generated/main/java/emu/grasscutter/net/proto/PlayerHomeCompInfoOuterClass.java
+++ b/src/generated/main/java/emu/grasscutter/net/proto/PlayerHomeCompInfoOuterClass.java
@@ -19,39 +19,39 @@ public final class PlayerHomeCompInfoOuterClass {
       com.google.protobuf.MessageOrBuilder {
 
     /**
-     * repeated uint32 unlocked_module_id_list = 3;
-     * @return A list containing the unlockedModuleIdList.
-     */
-    java.util.List getUnlockedModuleIdListList();
-    /**
-     * repeated uint32 unlocked_module_id_list = 3;
-     * @return The count of unlockedModuleIdList.
-     */
-    int getUnlockedModuleIdListCount();
-    /**
-     * repeated uint32 unlocked_module_id_list = 3;
-     * @param index The index of the element to return.
-     * @return The unlockedModuleIdList at the given index.
-     */
-    int getUnlockedModuleIdList(int index);
-
-    /**
-     * repeated uint32 levelup_reward_got_level_list = 10;
+     * repeated uint32 levelup_reward_got_level_list = 3;
      * @return A list containing the levelupRewardGotLevelList.
      */
     java.util.List getLevelupRewardGotLevelListList();
     /**
-     * repeated uint32 levelup_reward_got_level_list = 10;
+     * repeated uint32 levelup_reward_got_level_list = 3;
      * @return The count of levelupRewardGotLevelList.
      */
     int getLevelupRewardGotLevelListCount();
     /**
-     * repeated uint32 levelup_reward_got_level_list = 10;
+     * repeated uint32 levelup_reward_got_level_list = 3;
      * @param index The index of the element to return.
      * @return The levelupRewardGotLevelList at the given index.
      */
     int getLevelupRewardGotLevelList(int index);
 
+    /**
+     * repeated uint32 unlocked_module_id_list = 10;
+     * @return A list containing the unlockedModuleIdList.
+     */
+    java.util.List getUnlockedModuleIdListList();
+    /**
+     * repeated uint32 unlocked_module_id_list = 10;
+     * @return The count of unlockedModuleIdList.
+     */
+    int getUnlockedModuleIdListCount();
+    /**
+     * repeated uint32 unlocked_module_id_list = 10;
+     * @param index The index of the element to return.
+     * @return The unlockedModuleIdList at the given index.
+     */
+    int getUnlockedModuleIdList(int index);
+
     /**
      * repeated uint32 seen_module_id_list = 8;
      * @return A list containing the seenModuleIdList.
@@ -97,8 +97,8 @@ public final class PlayerHomeCompInfoOuterClass {
       super(builder);
     }
     private PlayerHomeCompInfo() {
-      unlockedModuleIdList_ = emptyIntList();
       levelupRewardGotLevelList_ = emptyIntList();
+      unlockedModuleIdList_ = emptyIntList();
       seenModuleIdList_ = emptyIntList();
       friendEnterHomeOption_ = 0;
     }
@@ -136,21 +136,21 @@ public final class PlayerHomeCompInfoOuterClass {
               break;
             case 24: {
               if (!((mutable_bitField0_ & 0x00000001) != 0)) {
-                unlockedModuleIdList_ = newIntList();
+                levelupRewardGotLevelList_ = newIntList();
                 mutable_bitField0_ |= 0x00000001;
               }
-              unlockedModuleIdList_.addInt(input.readUInt32());
+              levelupRewardGotLevelList_.addInt(input.readUInt32());
               break;
             }
             case 26: {
               int length = input.readRawVarint32();
               int limit = input.pushLimit(length);
               if (!((mutable_bitField0_ & 0x00000001) != 0) && input.getBytesUntilLimit() > 0) {
-                unlockedModuleIdList_ = newIntList();
+                levelupRewardGotLevelList_ = newIntList();
                 mutable_bitField0_ |= 0x00000001;
               }
               while (input.getBytesUntilLimit() > 0) {
-                unlockedModuleIdList_.addInt(input.readUInt32());
+                levelupRewardGotLevelList_.addInt(input.readUInt32());
               }
               input.popLimit(limit);
               break;
@@ -178,21 +178,21 @@ public final class PlayerHomeCompInfoOuterClass {
             }
             case 80: {
               if (!((mutable_bitField0_ & 0x00000002) != 0)) {
-                levelupRewardGotLevelList_ = newIntList();
+                unlockedModuleIdList_ = newIntList();
                 mutable_bitField0_ |= 0x00000002;
               }
-              levelupRewardGotLevelList_.addInt(input.readUInt32());
+              unlockedModuleIdList_.addInt(input.readUInt32());
               break;
             }
             case 82: {
               int length = input.readRawVarint32();
               int limit = input.pushLimit(length);
               if (!((mutable_bitField0_ & 0x00000002) != 0) && input.getBytesUntilLimit() > 0) {
-                levelupRewardGotLevelList_ = newIntList();
+                unlockedModuleIdList_ = newIntList();
                 mutable_bitField0_ |= 0x00000002;
               }
               while (input.getBytesUntilLimit() > 0) {
-                levelupRewardGotLevelList_.addInt(input.readUInt32());
+                unlockedModuleIdList_.addInt(input.readUInt32());
               }
               input.popLimit(limit);
               break;
@@ -219,13 +219,13 @@ public final class PlayerHomeCompInfoOuterClass {
             e).setUnfinishedMessage(this);
       } finally {
         if (((mutable_bitField0_ & 0x00000001) != 0)) {
-          unlockedModuleIdList_.makeImmutable(); // C
+          levelupRewardGotLevelList_.makeImmutable(); // C
         }
         if (((mutable_bitField0_ & 0x00000004) != 0)) {
           seenModuleIdList_.makeImmutable(); // C
         }
         if (((mutable_bitField0_ & 0x00000002) != 0)) {
-          levelupRewardGotLevelList_.makeImmutable(); // C
+          unlockedModuleIdList_.makeImmutable(); // C
         }
         this.unknownFields = unknownFields.build();
         makeExtensionsImmutable();
@@ -244,38 +244,10 @@ public final class PlayerHomeCompInfoOuterClass {
               emu.grasscutter.net.proto.PlayerHomeCompInfoOuterClass.PlayerHomeCompInfo.class, emu.grasscutter.net.proto.PlayerHomeCompInfoOuterClass.PlayerHomeCompInfo.Builder.class);
     }
 
-    public static final int UNLOCKED_MODULE_ID_LIST_FIELD_NUMBER = 3;
-    private com.google.protobuf.Internal.IntList unlockedModuleIdList_;
-    /**
-     * repeated uint32 unlocked_module_id_list = 3;
-     * @return A list containing the unlockedModuleIdList.
-     */
-    @java.lang.Override
-    public java.util.List
-        getUnlockedModuleIdListList() {
-      return unlockedModuleIdList_;
-    }
-    /**
-     * repeated uint32 unlocked_module_id_list = 3;
-     * @return The count of unlockedModuleIdList.
-     */
-    public int getUnlockedModuleIdListCount() {
-      return unlockedModuleIdList_.size();
-    }
-    /**
-     * repeated uint32 unlocked_module_id_list = 3;
-     * @param index The index of the element to return.
-     * @return The unlockedModuleIdList at the given index.
-     */
-    public int getUnlockedModuleIdList(int index) {
-      return unlockedModuleIdList_.getInt(index);
-    }
-    private int unlockedModuleIdListMemoizedSerializedSize = -1;
-
-    public static final int LEVELUP_REWARD_GOT_LEVEL_LIST_FIELD_NUMBER = 10;
+    public static final int LEVELUP_REWARD_GOT_LEVEL_LIST_FIELD_NUMBER = 3;
     private com.google.protobuf.Internal.IntList levelupRewardGotLevelList_;
     /**
-     * repeated uint32 levelup_reward_got_level_list = 10;
+     * repeated uint32 levelup_reward_got_level_list = 3;
      * @return A list containing the levelupRewardGotLevelList.
      */
     @java.lang.Override
@@ -284,14 +256,14 @@ public final class PlayerHomeCompInfoOuterClass {
       return levelupRewardGotLevelList_;
     }
     /**
-     * repeated uint32 levelup_reward_got_level_list = 10;
+     * repeated uint32 levelup_reward_got_level_list = 3;
      * @return The count of levelupRewardGotLevelList.
      */
     public int getLevelupRewardGotLevelListCount() {
       return levelupRewardGotLevelList_.size();
     }
     /**
-     * repeated uint32 levelup_reward_got_level_list = 10;
+     * repeated uint32 levelup_reward_got_level_list = 3;
      * @param index The index of the element to return.
      * @return The levelupRewardGotLevelList at the given index.
      */
@@ -300,6 +272,34 @@ public final class PlayerHomeCompInfoOuterClass {
     }
     private int levelupRewardGotLevelListMemoizedSerializedSize = -1;
 
+    public static final int UNLOCKED_MODULE_ID_LIST_FIELD_NUMBER = 10;
+    private com.google.protobuf.Internal.IntList unlockedModuleIdList_;
+    /**
+     * repeated uint32 unlocked_module_id_list = 10;
+     * @return A list containing the unlockedModuleIdList.
+     */
+    @java.lang.Override
+    public java.util.List
+        getUnlockedModuleIdListList() {
+      return unlockedModuleIdList_;
+    }
+    /**
+     * repeated uint32 unlocked_module_id_list = 10;
+     * @return The count of unlockedModuleIdList.
+     */
+    public int getUnlockedModuleIdListCount() {
+      return unlockedModuleIdList_.size();
+    }
+    /**
+     * repeated uint32 unlocked_module_id_list = 10;
+     * @param index The index of the element to return.
+     * @return The unlockedModuleIdList at the given index.
+     */
+    public int getUnlockedModuleIdList(int index) {
+      return unlockedModuleIdList_.getInt(index);
+    }
+    private int unlockedModuleIdListMemoizedSerializedSize = -1;
+
     public static final int SEEN_MODULE_ID_LIST_FIELD_NUMBER = 8;
     private com.google.protobuf.Internal.IntList seenModuleIdList_;
     /**
@@ -362,12 +362,12 @@ public final class PlayerHomeCompInfoOuterClass {
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
       getSerializedSize();
-      if (getUnlockedModuleIdListList().size() > 0) {
+      if (getLevelupRewardGotLevelListList().size() > 0) {
         output.writeUInt32NoTag(26);
-        output.writeUInt32NoTag(unlockedModuleIdListMemoizedSerializedSize);
+        output.writeUInt32NoTag(levelupRewardGotLevelListMemoizedSerializedSize);
       }
-      for (int i = 0; i < unlockedModuleIdList_.size(); i++) {
-        output.writeUInt32NoTag(unlockedModuleIdList_.getInt(i));
+      for (int i = 0; i < levelupRewardGotLevelList_.size(); i++) {
+        output.writeUInt32NoTag(levelupRewardGotLevelList_.getInt(i));
       }
       if (getSeenModuleIdListList().size() > 0) {
         output.writeUInt32NoTag(66);
@@ -376,12 +376,12 @@ public final class PlayerHomeCompInfoOuterClass {
       for (int i = 0; i < seenModuleIdList_.size(); i++) {
         output.writeUInt32NoTag(seenModuleIdList_.getInt(i));
       }
-      if (getLevelupRewardGotLevelListList().size() > 0) {
+      if (getUnlockedModuleIdListList().size() > 0) {
         output.writeUInt32NoTag(82);
-        output.writeUInt32NoTag(levelupRewardGotLevelListMemoizedSerializedSize);
+        output.writeUInt32NoTag(unlockedModuleIdListMemoizedSerializedSize);
       }
-      for (int i = 0; i < levelupRewardGotLevelList_.size(); i++) {
-        output.writeUInt32NoTag(levelupRewardGotLevelList_.getInt(i));
+      for (int i = 0; i < unlockedModuleIdList_.size(); i++) {
+        output.writeUInt32NoTag(unlockedModuleIdList_.getInt(i));
       }
       if (friendEnterHomeOption_ != emu.grasscutter.net.proto.FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.FRIEND_ENTER_HOME_OPTION_NEED_CONFIRM.getNumber()) {
         output.writeEnum(15, friendEnterHomeOption_);
@@ -397,17 +397,17 @@ public final class PlayerHomeCompInfoOuterClass {
       size = 0;
       {
         int dataSize = 0;
-        for (int i = 0; i < unlockedModuleIdList_.size(); i++) {
+        for (int i = 0; i < levelupRewardGotLevelList_.size(); i++) {
           dataSize += com.google.protobuf.CodedOutputStream
-            .computeUInt32SizeNoTag(unlockedModuleIdList_.getInt(i));
+            .computeUInt32SizeNoTag(levelupRewardGotLevelList_.getInt(i));
         }
         size += dataSize;
-        if (!getUnlockedModuleIdListList().isEmpty()) {
+        if (!getLevelupRewardGotLevelListList().isEmpty()) {
           size += 1;
           size += com.google.protobuf.CodedOutputStream
               .computeInt32SizeNoTag(dataSize);
         }
-        unlockedModuleIdListMemoizedSerializedSize = dataSize;
+        levelupRewardGotLevelListMemoizedSerializedSize = dataSize;
       }
       {
         int dataSize = 0;
@@ -425,17 +425,17 @@ public final class PlayerHomeCompInfoOuterClass {
       }
       {
         int dataSize = 0;
-        for (int i = 0; i < levelupRewardGotLevelList_.size(); i++) {
+        for (int i = 0; i < unlockedModuleIdList_.size(); i++) {
           dataSize += com.google.protobuf.CodedOutputStream
-            .computeUInt32SizeNoTag(levelupRewardGotLevelList_.getInt(i));
+            .computeUInt32SizeNoTag(unlockedModuleIdList_.getInt(i));
         }
         size += dataSize;
-        if (!getLevelupRewardGotLevelListList().isEmpty()) {
+        if (!getUnlockedModuleIdListList().isEmpty()) {
           size += 1;
           size += com.google.protobuf.CodedOutputStream
               .computeInt32SizeNoTag(dataSize);
         }
-        levelupRewardGotLevelListMemoizedSerializedSize = dataSize;
+        unlockedModuleIdListMemoizedSerializedSize = dataSize;
       }
       if (friendEnterHomeOption_ != emu.grasscutter.net.proto.FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.FRIEND_ENTER_HOME_OPTION_NEED_CONFIRM.getNumber()) {
         size += com.google.protobuf.CodedOutputStream
@@ -456,10 +456,10 @@ public final class PlayerHomeCompInfoOuterClass {
       }
       emu.grasscutter.net.proto.PlayerHomeCompInfoOuterClass.PlayerHomeCompInfo other = (emu.grasscutter.net.proto.PlayerHomeCompInfoOuterClass.PlayerHomeCompInfo) obj;
 
-      if (!getUnlockedModuleIdListList()
-          .equals(other.getUnlockedModuleIdListList())) return false;
       if (!getLevelupRewardGotLevelListList()
           .equals(other.getLevelupRewardGotLevelListList())) return false;
+      if (!getUnlockedModuleIdListList()
+          .equals(other.getUnlockedModuleIdListList())) return false;
       if (!getSeenModuleIdListList()
           .equals(other.getSeenModuleIdListList())) return false;
       if (friendEnterHomeOption_ != other.friendEnterHomeOption_) return false;
@@ -474,14 +474,14 @@ public final class PlayerHomeCompInfoOuterClass {
       }
       int hash = 41;
       hash = (19 * hash) + getDescriptor().hashCode();
-      if (getUnlockedModuleIdListCount() > 0) {
-        hash = (37 * hash) + UNLOCKED_MODULE_ID_LIST_FIELD_NUMBER;
-        hash = (53 * hash) + getUnlockedModuleIdListList().hashCode();
-      }
       if (getLevelupRewardGotLevelListCount() > 0) {
         hash = (37 * hash) + LEVELUP_REWARD_GOT_LEVEL_LIST_FIELD_NUMBER;
         hash = (53 * hash) + getLevelupRewardGotLevelListList().hashCode();
       }
+      if (getUnlockedModuleIdListCount() > 0) {
+        hash = (37 * hash) + UNLOCKED_MODULE_ID_LIST_FIELD_NUMBER;
+        hash = (53 * hash) + getUnlockedModuleIdListList().hashCode();
+      }
       if (getSeenModuleIdListCount() > 0) {
         hash = (37 * hash) + SEEN_MODULE_ID_LIST_FIELD_NUMBER;
         hash = (53 * hash) + getSeenModuleIdListList().hashCode();
@@ -625,9 +625,9 @@ public final class PlayerHomeCompInfoOuterClass {
       @java.lang.Override
       public Builder clear() {
         super.clear();
-        unlockedModuleIdList_ = emptyIntList();
-        bitField0_ = (bitField0_ & ~0x00000001);
         levelupRewardGotLevelList_ = emptyIntList();
+        bitField0_ = (bitField0_ & ~0x00000001);
+        unlockedModuleIdList_ = emptyIntList();
         bitField0_ = (bitField0_ & ~0x00000002);
         seenModuleIdList_ = emptyIntList();
         bitField0_ = (bitField0_ & ~0x00000004);
@@ -661,15 +661,15 @@ public final class PlayerHomeCompInfoOuterClass {
         emu.grasscutter.net.proto.PlayerHomeCompInfoOuterClass.PlayerHomeCompInfo result = new emu.grasscutter.net.proto.PlayerHomeCompInfoOuterClass.PlayerHomeCompInfo(this);
         int from_bitField0_ = bitField0_;
         if (((bitField0_ & 0x00000001) != 0)) {
-          unlockedModuleIdList_.makeImmutable();
+          levelupRewardGotLevelList_.makeImmutable();
           bitField0_ = (bitField0_ & ~0x00000001);
         }
-        result.unlockedModuleIdList_ = unlockedModuleIdList_;
+        result.levelupRewardGotLevelList_ = levelupRewardGotLevelList_;
         if (((bitField0_ & 0x00000002) != 0)) {
-          levelupRewardGotLevelList_.makeImmutable();
+          unlockedModuleIdList_.makeImmutable();
           bitField0_ = (bitField0_ & ~0x00000002);
         }
-        result.levelupRewardGotLevelList_ = levelupRewardGotLevelList_;
+        result.unlockedModuleIdList_ = unlockedModuleIdList_;
         if (((bitField0_ & 0x00000004) != 0)) {
           seenModuleIdList_.makeImmutable();
           bitField0_ = (bitField0_ & ~0x00000004);
@@ -724,26 +724,26 @@ public final class PlayerHomeCompInfoOuterClass {
 
       public Builder mergeFrom(emu.grasscutter.net.proto.PlayerHomeCompInfoOuterClass.PlayerHomeCompInfo other) {
         if (other == emu.grasscutter.net.proto.PlayerHomeCompInfoOuterClass.PlayerHomeCompInfo.getDefaultInstance()) return this;
-        if (!other.unlockedModuleIdList_.isEmpty()) {
-          if (unlockedModuleIdList_.isEmpty()) {
-            unlockedModuleIdList_ = other.unlockedModuleIdList_;
-            bitField0_ = (bitField0_ & ~0x00000001);
-          } else {
-            ensureUnlockedModuleIdListIsMutable();
-            unlockedModuleIdList_.addAll(other.unlockedModuleIdList_);
-          }
-          onChanged();
-        }
         if (!other.levelupRewardGotLevelList_.isEmpty()) {
           if (levelupRewardGotLevelList_.isEmpty()) {
             levelupRewardGotLevelList_ = other.levelupRewardGotLevelList_;
-            bitField0_ = (bitField0_ & ~0x00000002);
+            bitField0_ = (bitField0_ & ~0x00000001);
           } else {
             ensureLevelupRewardGotLevelListIsMutable();
             levelupRewardGotLevelList_.addAll(other.levelupRewardGotLevelList_);
           }
           onChanged();
         }
+        if (!other.unlockedModuleIdList_.isEmpty()) {
+          if (unlockedModuleIdList_.isEmpty()) {
+            unlockedModuleIdList_ = other.unlockedModuleIdList_;
+            bitField0_ = (bitField0_ & ~0x00000002);
+          } else {
+            ensureUnlockedModuleIdListIsMutable();
+            unlockedModuleIdList_.addAll(other.unlockedModuleIdList_);
+          }
+          onChanged();
+        }
         if (!other.seenModuleIdList_.isEmpty()) {
           if (seenModuleIdList_.isEmpty()) {
             seenModuleIdList_ = other.seenModuleIdList_;
@@ -787,110 +787,31 @@ public final class PlayerHomeCompInfoOuterClass {
       }
       private int bitField0_;
 
-      private com.google.protobuf.Internal.IntList unlockedModuleIdList_ = emptyIntList();
-      private void ensureUnlockedModuleIdListIsMutable() {
+      private com.google.protobuf.Internal.IntList levelupRewardGotLevelList_ = emptyIntList();
+      private void ensureLevelupRewardGotLevelListIsMutable() {
         if (!((bitField0_ & 0x00000001) != 0)) {
-          unlockedModuleIdList_ = mutableCopy(unlockedModuleIdList_);
+          levelupRewardGotLevelList_ = mutableCopy(levelupRewardGotLevelList_);
           bitField0_ |= 0x00000001;
          }
       }
       /**
-       * repeated uint32 unlocked_module_id_list = 3;
-       * @return A list containing the unlockedModuleIdList.
-       */
-      public java.util.List
-          getUnlockedModuleIdListList() {
-        return ((bitField0_ & 0x00000001) != 0) ?
-                 java.util.Collections.unmodifiableList(unlockedModuleIdList_) : unlockedModuleIdList_;
-      }
-      /**
-       * repeated uint32 unlocked_module_id_list = 3;
-       * @return The count of unlockedModuleIdList.
-       */
-      public int getUnlockedModuleIdListCount() {
-        return unlockedModuleIdList_.size();
-      }
-      /**
-       * repeated uint32 unlocked_module_id_list = 3;
-       * @param index The index of the element to return.
-       * @return The unlockedModuleIdList at the given index.
-       */
-      public int getUnlockedModuleIdList(int index) {
-        return unlockedModuleIdList_.getInt(index);
-      }
-      /**
-       * repeated uint32 unlocked_module_id_list = 3;
-       * @param index The index to set the value at.
-       * @param value The unlockedModuleIdList to set.
-       * @return This builder for chaining.
-       */
-      public Builder setUnlockedModuleIdList(
-          int index, int value) {
-        ensureUnlockedModuleIdListIsMutable();
-        unlockedModuleIdList_.setInt(index, value);
-        onChanged();
-        return this;
-      }
-      /**
-       * repeated uint32 unlocked_module_id_list = 3;
-       * @param value The unlockedModuleIdList to add.
-       * @return This builder for chaining.
-       */
-      public Builder addUnlockedModuleIdList(int value) {
-        ensureUnlockedModuleIdListIsMutable();
-        unlockedModuleIdList_.addInt(value);
-        onChanged();
-        return this;
-      }
-      /**
-       * repeated uint32 unlocked_module_id_list = 3;
-       * @param values The unlockedModuleIdList to add.
-       * @return This builder for chaining.
-       */
-      public Builder addAllUnlockedModuleIdList(
-          java.lang.Iterable values) {
-        ensureUnlockedModuleIdListIsMutable();
-        com.google.protobuf.AbstractMessageLite.Builder.addAll(
-            values, unlockedModuleIdList_);
-        onChanged();
-        return this;
-      }
-      /**
-       * repeated uint32 unlocked_module_id_list = 3;
-       * @return This builder for chaining.
-       */
-      public Builder clearUnlockedModuleIdList() {
-        unlockedModuleIdList_ = emptyIntList();
-        bitField0_ = (bitField0_ & ~0x00000001);
-        onChanged();
-        return this;
-      }
-
-      private com.google.protobuf.Internal.IntList levelupRewardGotLevelList_ = emptyIntList();
-      private void ensureLevelupRewardGotLevelListIsMutable() {
-        if (!((bitField0_ & 0x00000002) != 0)) {
-          levelupRewardGotLevelList_ = mutableCopy(levelupRewardGotLevelList_);
-          bitField0_ |= 0x00000002;
-         }
-      }
-      /**
-       * repeated uint32 levelup_reward_got_level_list = 10;
+       * repeated uint32 levelup_reward_got_level_list = 3;
        * @return A list containing the levelupRewardGotLevelList.
        */
       public java.util.List
           getLevelupRewardGotLevelListList() {
-        return ((bitField0_ & 0x00000002) != 0) ?
+        return ((bitField0_ & 0x00000001) != 0) ?
                  java.util.Collections.unmodifiableList(levelupRewardGotLevelList_) : levelupRewardGotLevelList_;
       }
       /**
-       * repeated uint32 levelup_reward_got_level_list = 10;
+       * repeated uint32 levelup_reward_got_level_list = 3;
        * @return The count of levelupRewardGotLevelList.
        */
       public int getLevelupRewardGotLevelListCount() {
         return levelupRewardGotLevelList_.size();
       }
       /**
-       * repeated uint32 levelup_reward_got_level_list = 10;
+       * repeated uint32 levelup_reward_got_level_list = 3;
        * @param index The index of the element to return.
        * @return The levelupRewardGotLevelList at the given index.
        */
@@ -898,7 +819,7 @@ public final class PlayerHomeCompInfoOuterClass {
         return levelupRewardGotLevelList_.getInt(index);
       }
       /**
-       * repeated uint32 levelup_reward_got_level_list = 10;
+       * repeated uint32 levelup_reward_got_level_list = 3;
        * @param index The index to set the value at.
        * @param value The levelupRewardGotLevelList to set.
        * @return This builder for chaining.
@@ -911,7 +832,7 @@ public final class PlayerHomeCompInfoOuterClass {
         return this;
       }
       /**
-       * repeated uint32 levelup_reward_got_level_list = 10;
+       * repeated uint32 levelup_reward_got_level_list = 3;
        * @param value The levelupRewardGotLevelList to add.
        * @return This builder for chaining.
        */
@@ -922,7 +843,7 @@ public final class PlayerHomeCompInfoOuterClass {
         return this;
       }
       /**
-       * repeated uint32 levelup_reward_got_level_list = 10;
+       * repeated uint32 levelup_reward_got_level_list = 3;
        * @param values The levelupRewardGotLevelList to add.
        * @return This builder for chaining.
        */
@@ -935,11 +856,90 @@ public final class PlayerHomeCompInfoOuterClass {
         return this;
       }
       /**
-       * repeated uint32 levelup_reward_got_level_list = 10;
+       * repeated uint32 levelup_reward_got_level_list = 3;
        * @return This builder for chaining.
        */
       public Builder clearLevelupRewardGotLevelList() {
         levelupRewardGotLevelList_ = emptyIntList();
+        bitField0_ = (bitField0_ & ~0x00000001);
+        onChanged();
+        return this;
+      }
+
+      private com.google.protobuf.Internal.IntList unlockedModuleIdList_ = emptyIntList();
+      private void ensureUnlockedModuleIdListIsMutable() {
+        if (!((bitField0_ & 0x00000002) != 0)) {
+          unlockedModuleIdList_ = mutableCopy(unlockedModuleIdList_);
+          bitField0_ |= 0x00000002;
+         }
+      }
+      /**
+       * repeated uint32 unlocked_module_id_list = 10;
+       * @return A list containing the unlockedModuleIdList.
+       */
+      public java.util.List
+          getUnlockedModuleIdListList() {
+        return ((bitField0_ & 0x00000002) != 0) ?
+                 java.util.Collections.unmodifiableList(unlockedModuleIdList_) : unlockedModuleIdList_;
+      }
+      /**
+       * repeated uint32 unlocked_module_id_list = 10;
+       * @return The count of unlockedModuleIdList.
+       */
+      public int getUnlockedModuleIdListCount() {
+        return unlockedModuleIdList_.size();
+      }
+      /**
+       * repeated uint32 unlocked_module_id_list = 10;
+       * @param index The index of the element to return.
+       * @return The unlockedModuleIdList at the given index.
+       */
+      public int getUnlockedModuleIdList(int index) {
+        return unlockedModuleIdList_.getInt(index);
+      }
+      /**
+       * repeated uint32 unlocked_module_id_list = 10;
+       * @param index The index to set the value at.
+       * @param value The unlockedModuleIdList to set.
+       * @return This builder for chaining.
+       */
+      public Builder setUnlockedModuleIdList(
+          int index, int value) {
+        ensureUnlockedModuleIdListIsMutable();
+        unlockedModuleIdList_.setInt(index, value);
+        onChanged();
+        return this;
+      }
+      /**
+       * repeated uint32 unlocked_module_id_list = 10;
+       * @param value The unlockedModuleIdList to add.
+       * @return This builder for chaining.
+       */
+      public Builder addUnlockedModuleIdList(int value) {
+        ensureUnlockedModuleIdListIsMutable();
+        unlockedModuleIdList_.addInt(value);
+        onChanged();
+        return this;
+      }
+      /**
+       * repeated uint32 unlocked_module_id_list = 10;
+       * @param values The unlockedModuleIdList to add.
+       * @return This builder for chaining.
+       */
+      public Builder addAllUnlockedModuleIdList(
+          java.lang.Iterable values) {
+        ensureUnlockedModuleIdListIsMutable();
+        com.google.protobuf.AbstractMessageLite.Builder.addAll(
+            values, unlockedModuleIdList_);
+        onChanged();
+        return this;
+      }
+      /**
+       * repeated uint32 unlocked_module_id_list = 10;
+       * @return This builder for chaining.
+       */
+      public Builder clearUnlockedModuleIdList() {
+        unlockedModuleIdList_ = emptyIntList();
         bitField0_ = (bitField0_ & ~0x00000002);
         onChanged();
         return this;
@@ -1145,9 +1145,9 @@ public final class PlayerHomeCompInfoOuterClass {
   static {
     java.lang.String[] descriptorData = {
       "\n\030PlayerHomeCompInfo.proto\032\033FriendEnterH" +
-      "omeOption.proto\"\263\001\n\022PlayerHomeCompInfo\022\037" +
-      "\n\027unlocked_module_id_list\030\003 \003(\r\022%\n\035level" +
-      "up_reward_got_level_list\030\n \003(\r\022\033\n\023seen_m" +
+      "omeOption.proto\"\263\001\n\022PlayerHomeCompInfo\022%" +
+      "\n\035levelup_reward_got_level_list\030\003 \003(\r\022\037\n" +
+      "\027unlocked_module_id_list\030\n \003(\r\022\033\n\023seen_m" +
       "odule_id_list\030\010 \003(\r\0228\n\030friend_enter_home" +
       "_option\030\017 \001(\0162\026.FriendEnterHomeOptionB\033\n" +
       "\031emu.grasscutter.net.protob\006proto3"
@@ -1162,7 +1162,7 @@ public final class PlayerHomeCompInfoOuterClass {
     internal_static_PlayerHomeCompInfo_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_PlayerHomeCompInfo_descriptor,
-        new java.lang.String[] { "UnlockedModuleIdList", "LevelupRewardGotLevelList", "SeenModuleIdList", "FriendEnterHomeOption", });
+        new java.lang.String[] { "LevelupRewardGotLevelList", "UnlockedModuleIdList", "SeenModuleIdList", "FriendEnterHomeOption", });
     emu.grasscutter.net.proto.FriendEnterHomeOptionOuterClass.getDescriptor();
   }
 
diff --git a/src/main/java/emu/grasscutter/data/binout/HomeworldDefaultSaveData.java b/src/main/java/emu/grasscutter/data/binout/HomeworldDefaultSaveData.java
index 3916f125f..30f997e10 100644
--- a/src/main/java/emu/grasscutter/data/binout/HomeworldDefaultSaveData.java
+++ b/src/main/java/emu/grasscutter/data/binout/HomeworldDefaultSaveData.java
@@ -2,11 +2,12 @@ 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 {
diff --git a/src/main/java/emu/grasscutter/data/excels/HomeWorldBgmData.java b/src/main/java/emu/grasscutter/data/excels/HomeWorldBgmData.java
index 65f7498e6..899b98b42 100644
--- a/src/main/java/emu/grasscutter/data/excels/HomeWorldBgmData.java
+++ b/src/main/java/emu/grasscutter/data/excels/HomeWorldBgmData.java
@@ -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;
diff --git a/src/main/java/emu/grasscutter/game/friends/Friendship.java b/src/main/java/emu/grasscutter/game/friends/Friendship.java
index 5eb65a628..3e28e9aa6 100644
--- a/src/main/java/emu/grasscutter/game/friends/Friendship.java
+++ b/src/main/java/emu/grasscutter/game/friends/Friendship.java
@@ -109,6 +109,7 @@ public class Friendship {
                         .setParam(getFriendProfile().getDaysSinceLogin())
                         .setIsGameSource(true)
                         .setPlatformType(PlatformTypeOuterClass.PlatformType.PLATFORM_TYPE_PC)
+                        .setFriendEnterHomeOptionValue(getFriendProfile().getEnterHomeOption())
                         .build();
 
         return proto;
diff --git a/src/main/java/emu/grasscutter/game/friends/PlayerProfile.java b/src/main/java/emu/grasscutter/game/friends/PlayerProfile.java
index 3f23aece8..b6676e9d7 100644
--- a/src/main/java/emu/grasscutter/game/friends/PlayerProfile.java
+++ b/src/main/java/emu/grasscutter/game/friends/PlayerProfile.java
@@ -3,8 +3,11 @@ package emu.grasscutter.game.friends;
 import dev.morphia.annotations.AlsoLoad;
 import dev.morphia.annotations.Entity;
 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;
 
 @Entity
 public class PlayerProfile {
@@ -17,11 +20,12 @@ public class PlayerProfile {
     private int avatarId;
     private String name;
     private String signature;
-    private int achievements;
 
     private int playerLevel;
     private int worldLevel;
     private int lastActiveTime;
+    @Getter
+    private int enterHomeOption;
 
     @Deprecated // Morphia only
     public PlayerProfile() {}
@@ -59,10 +63,6 @@ public class PlayerProfile {
         return signature;
     }
 
-    public int getAchievements() {
-        return achievements;
-    }
-
     public int getPlayerLevel() {
         return playerLevel;
     }
@@ -99,7 +99,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();
     }
 }
diff --git a/src/main/java/emu/grasscutter/game/home/EnterHomeRequest.java b/src/main/java/emu/grasscutter/game/home/EnterHomeRequest.java
new file mode 100644
index 000000000..defa8928b
--- /dev/null
+++ b/src/main/java/emu/grasscutter/game/home/EnterHomeRequest.java
@@ -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);
+    }
+}
diff --git a/src/main/java/emu/grasscutter/game/home/GameHome.java b/src/main/java/emu/grasscutter/game/home/GameHome.java
index bc8a1f98f..250a0e25a 100644
--- a/src/main/java/emu/grasscutter/game/home/GameHome.java
+++ b/src/main/java/emu/grasscutter/game/home/GameHome.java
@@ -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 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 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
diff --git a/src/main/java/emu/grasscutter/game/home/HomeWorld.java b/src/main/java/emu/grasscutter/game/home/HomeWorld.java
new file mode 100644
index 000000000..592d385e7
--- /dev/null
+++ b/src/main/java/emu/grasscutter/game/home/HomeWorld.java
@@ -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 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);
+        }
+    }
+}
diff --git a/src/main/java/emu/grasscutter/game/home/HomeWorldMPSystem.java b/src/main/java/emu/grasscutter/game/home/HomeWorldMPSystem.java
new file mode 100644
index 000000000..1cd8b06d8
--- /dev/null
+++ b/src/main/java/emu/grasscutter/game/home/HomeWorldMPSystem.java
@@ -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;
+    }
+}
diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java
index 3789f1183..e84e433f4 100644
--- a/src/main/java/emu/grasscutter/game/player/Player.java
+++ b/src/main/java/emu/grasscutter/game/player/Player.java
@@ -21,7 +21,9 @@ import emu.grasscutter.game.expedition.ExpeditionInfo;
 import emu.grasscutter.game.friends.FriendsList;
 import emu.grasscutter.game.friends.PlayerProfile;
 import emu.grasscutter.game.gacha.PlayerGachaInfo;
+import emu.grasscutter.game.home.EnterHomeRequest;
 import emu.grasscutter.game.home.GameHome;
+import emu.grasscutter.game.home.HomeWorld;
 import emu.grasscutter.game.inventory.GameItem;
 import emu.grasscutter.game.inventory.Inventory;
 import emu.grasscutter.game.mail.Mail;
@@ -29,6 +31,7 @@ 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;
@@ -38,7 +41,6 @@ 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.SotSManager;
 import emu.grasscutter.game.managers.stamina.StaminaManager;
 import emu.grasscutter.game.props.*;
 import emu.grasscutter.game.quest.QuestManager;
@@ -58,15 +60,13 @@ import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
 import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
 import emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType;
 import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo;
-import emu.grasscutter.net.proto.PlayerApplyEnterMpResultNotifyOuterClass;
+import emu.grasscutter.net.proto.*;
 import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo;
-import emu.grasscutter.net.proto.PlayerWorldLocationInfoOuterClass;
 import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
 import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
-import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass;
 import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
-import emu.grasscutter.net.proto.SocialShowAvatarInfoOuterClass;
 import emu.grasscutter.plugin.api.PlayerHook;
+import emu.grasscutter.scripts.ScriptLoader;
 import emu.grasscutter.scripts.data.SceneRegion;
 import emu.grasscutter.server.event.player.PlayerEnterAreaEvent;
 import emu.grasscutter.server.event.player.PlayerJoinEvent;
@@ -75,7 +75,8 @@ import emu.grasscutter.server.game.GameServer;
 import emu.grasscutter.server.game.GameSession;
 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.Int2ObjectMap;
@@ -108,6 +109,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;
@@ -116,6 +119,7 @@ public class Player implements PlayerHook, FieldFetch {
     @Getter @Setter private List showNameCardList;
     @Getter private Map 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;
@@ -148,6 +152,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;
@@ -202,6 +208,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 enterHomeRequests;
 
     private transient final Int2ObjectMap coopRequests;  // Synchronized getter
     @Getter private transient final Queue attackResults;
@@ -238,6 +245,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;
@@ -274,6 +282,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);
@@ -494,6 +503,18 @@ public class Player implements PlayerHook, FieldFetch {
         this.seenRealmList.add(seenId);
     }
 
+    public Optional 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;
@@ -716,7 +737,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());
@@ -1201,6 +1222,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) {
@@ -1209,6 +1245,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
@@ -1322,9 +1360,9 @@ public class Player implements PlayerHook, FieldFetch {
         }
 
         // Load from db
-        var runner = Grasscutter.getThreadPool();
-        runner.submit(() -> this.achievements = Achievements.getByPlayer(this));
+        this.achievements = Achievements.getByPlayer(this);
 
+        var runner = Grasscutter.getThreadPool();
         runner.submit(this.getAvatars()::loadFromDatabase);
         runner.submit(this.getInventory()::loadFromDatabase);
 
@@ -1365,6 +1403,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);
@@ -1413,7 +1461,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);
@@ -1461,6 +1512,8 @@ public class Player implements PlayerHook, FieldFetch {
             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();
diff --git a/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseUnlockHomeModule.java b/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseUnlockHomeModule.java
index e601e6b29..c36564d1c 100644
--- a/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseUnlockHomeModule.java
+++ b/src/main/java/emu/grasscutter/game/props/ItemUseAction/ItemUseUnlockHomeModule.java
@@ -14,6 +14,7 @@ public class ItemUseUnlockHomeModule extends ItemUseInt {
 
     @Override
     public boolean useItem(UseItemParams params) {
-        return false;
+        params.player.addRealmList(this.i);
+        return true;
     }
 }
diff --git a/src/main/java/emu/grasscutter/game/systems/MultiplayerSystem.java b/src/main/java/emu/grasscutter/game/systems/MultiplayerSystem.java
index 3eb2a79a1..beef7c51d 100644
--- a/src/main/java/emu/grasscutter/game/systems/MultiplayerSystem.java
+++ b/src/main/java/emu/grasscutter/game/systems/MultiplayerSystem.java
@@ -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;
diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java
index 55bfc22be..3f535289c 100644
--- a/src/main/java/emu/grasscutter/game/world/Scene.java
+++ b/src/main/java/emu/grasscutter/game/world/Scene.java
@@ -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,35 +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.AttackResultOuterClass.AttackResult;
-import emu.grasscutter.net.proto.*;
+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.*;
+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;
 
 public final class Scene {
@@ -260,6 +270,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();
diff --git a/src/main/java/emu/grasscutter/game/world/World.java b/src/main/java/emu/grasscutter/game/world/World.java
index 5f1e8b952..8336556a6 100644
--- a/src/main/java/emu/grasscutter/game/world/World.java
+++ b/src/main/java/emu/grasscutter/game/world/World.java
@@ -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 {
     @Getter private final GameServer server;
-    @Getter private final Player host;
+    @Getter private Player host;
     @Getter private final List players;
     @Getter private final Int2ObjectMap scenes;
 
@@ -65,6 +77,15 @@ public class World implements Iterable {
         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 {
         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 {
         }
     }
 
+    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 {
         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 {
             }
 
             // 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));
diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerEnterHomeEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerEnterHomeEvent.java
new file mode 100644
index 000000000..0cc673bca
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/event/player/PlayerEnterHomeEvent.java
@@ -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);
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerLeaveHomeEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerLeaveHomeEvent.java
new file mode 100644
index 000000000..f91d8feb2
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/event/player/PlayerLeaveHomeEvent.java
@@ -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
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java
index 6e67d970c..061700586 100644
--- a/src/main/java/emu/grasscutter/server/game/GameServer.java
+++ b/src/main/java/emu/grasscutter/server/game/GameServer.java
@@ -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 {
@@ -48,6 +70,7 @@ public final class GameServer extends KcpServer implements Iterable {
     private final GameServerPacketHandler packetHandler;
     private final Map players;
     private final Set worlds;
+    private final Int2ObjectMap homeWorlds;
 
     @Setter private DispatchClient dispatchClient;
 
@@ -56,6 +79,7 @@ public final class GameServer extends KcpServer implements Iterable {
     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 {
             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 {
         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 {
         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 {
         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 {
         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.
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerBackMyWorldReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBackMyWorldReq.java
index 6b1b7c58a..7c1d38060 100644
--- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerBackMyWorldReq.java
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBackMyWorldReq.java
@@ -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));
     }
 }
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java
index aa7219794..6450f5833 100644
--- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java
@@ -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();
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeBgmReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeBgmReq.java
index 75e9f36d4..8612d3924 100644
--- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeBgmReq.java
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeBgmReq.java
@@ -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());
     }
 }
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeEditModeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeEditModeReq.java
index 6e3b7ad31..f6b07875d 100644
--- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeEditModeReq.java
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeEditModeReq.java
@@ -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()));
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeGetOnlineStatusReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeGetOnlineStatusReq.java
new file mode 100644
index 000000000..02cf64ca3
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeGetOnlineStatusReq.java
@@ -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()));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeKickPlayerReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeKickPlayerReq.java
new file mode 100644
index 000000000..87db6bf0d
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeKickPlayerReq.java
@@ -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));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSaveArrangementNoChangeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSaveArrangementNoChangeReq.java
new file mode 100644
index 000000000..3c470e057
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSaveArrangementNoChangeReq.java
@@ -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()));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSceneInitFinishReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSceneInitFinishReq.java
index e71debf64..d151632cc 100644
--- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSceneInitFinishReq.java
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSceneInitFinishReq.java
@@ -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());
     }
 }
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSceneJumpReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSceneJumpReq.java
index b87968793..e1e914940 100644
--- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSceneJumpReq.java
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSceneJumpReq.java
@@ -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()));
     }
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeTransferReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeTransferReq.java
new file mode 100644
index 000000000..26b3f664b
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeTransferReq.java
@@ -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 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));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUpdateArrangementInfoReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUpdateArrangementInfoReq.java
index d94065d81..d2724ed13 100644
--- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUpdateArrangementInfoReq.java
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUpdateArrangementInfoReq.java
@@ -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());
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterHomeResultReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterHomeResultReq.java
new file mode 100644
index 000000000..dd8812534
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterHomeResultReq.java
@@ -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()));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java
index 68ec0d5c5..c3184719a 100644
--- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneTransToPointReq.java
@@ -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;
             }
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java
index 2f29e3826..5d3b14016 100644
--- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTryEnterHomeReq.java
@@ -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);
     }
 }
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketBackMyWorldRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketBackMyWorldRsp.java
index 90e02ca73..79be2eab3 100644
--- a/src/main/java/emu/grasscutter/server/packet/send/PacketBackMyWorldRsp.java
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketBackMyWorldRsp.java
@@ -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());
     }
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java
index 9001ae0c3..86e60e0d0 100644
--- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java
@@ -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 =
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java
index f8654de18..d12c6b1f7 100644
--- a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java
@@ -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);
     }
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeChangeEditModeRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeChangeEditModeRsp.java
index 9a2f91cc4..cd63b730f 100644
--- a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeChangeEditModeRsp.java
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeChangeEditModeRsp.java
@@ -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));
+    }
 }
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeGetArrangementInfoRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeGetArrangementInfoRsp.java
index ec76b18c8..54488c939 100644
--- a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeGetArrangementInfoRsp.java
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeGetArrangementInfoRsp.java
@@ -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 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);
     }
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeGetOnlineStatusRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeGetOnlineStatusRsp.java
new file mode 100644
index 000000000..d9c18a0e3
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeGetOnlineStatusRsp.java
@@ -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 guests) {
+        super(PacketOpcodes.HomeGetOnlineStatusRsp);
+
+        this.setData(HomeGetOnlineStatusRspOuterClass.HomeGetOnlineStatusRsp.newBuilder()
+            .addAllPlayerInfoList(guests.stream().map(Player::getOnlinePlayerInfo).toList()));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeKickPlayerRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeKickPlayerRsp.java
new file mode 100644
index 000000000..694094ed2
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeKickPlayerRsp.java
@@ -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));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeMarkPointNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeMarkPointNotify.java
index a5793d596..750d981ca 100644
--- a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeMarkPointNotify.java
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeMarkPointNotify.java
@@ -6,6 +6,7 @@ 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 java.util.Collection;
 
 public class PacketHomeMarkPointNotify extends BasePacket {
@@ -14,28 +15,32 @@ public class PacketHomeMarkPointNotify extends BasePacket {
         super(PacketOpcodes.HomeMarkPointNotify);
 
         var proto = HomeMarkPointNotifyOuterClass.HomeMarkPointNotify.newBuilder();
+        var owner = player.getCurHomeWorld().getHost();
+        var home = player.getCurHomeWorld().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.getBornPos().toProto())
+                    .setTeapotSpiritPos(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();
+                homeScene.getBlockItems().values().stream()
+                    .map(HomeBlockItem::getDeployFurnitureList)
+                    .flatMap(Collection::stream)
+                    .filter(i -> i.getFurnitureId() == 373501)
+                    .map(x -> x.toMarkPointProto(3))
+                    .toList();
 
             markPointData.addAllFurnitureList(marks);
             proto.addMarkPointDataList(markPointData);
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeSaveArrangementNoChangeRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeSaveArrangementNoChangeRsp.java
new file mode 100644
index 000000000..11008d864
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeSaveArrangementNoChangeRsp.java
@@ -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));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketOtherPlayerEnterOrLeaveHomeNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketOtherPlayerEnterOrLeaveHomeNotify.java
new file mode 100644
index 000000000..ec2417102
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketOtherPlayerEnterOrLeaveHomeNotify.java
@@ -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));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerApplyEnterHomeNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerApplyEnterHomeNotify.java
new file mode 100644
index 000000000..834c57d34
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerApplyEnterHomeNotify.java
@@ -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()));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerApplyEnterHomeResultNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerApplyEnterHomeResultNotify.java
new file mode 100644
index 000000000..b2b5df58b
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerApplyEnterHomeResultNotify.java
@@ -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));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerApplyEnterHomeResultRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerApplyEnterHomeResultRsp.java
new file mode 100644
index 000000000..63194ae8b
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerApplyEnterHomeResultRsp.java
@@ -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));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java
index 145c8cab1..4b78d81f1 100644
--- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java
@@ -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);
+    }
 }
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerHomeCompInfoNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerHomeCompInfoNotify.java
index 7335634a1..8e0024e78 100644
--- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerHomeCompInfoNotify.java
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerHomeCompInfoNotify.java
@@ -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();
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerPreEnterMpNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerPreEnterMpNotify.java
new file mode 100644
index 000000000..e4213e43d
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerPreEnterMpNotify.java
@@ -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));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketTryEnterHomeRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketTryEnterHomeRsp.java
index 76e4ada48..5d5344e0e 100644
--- a/src/main/java/emu/grasscutter/server/packet/send/PacketTryEnterHomeRsp.java
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketTryEnterHomeRsp.java
@@ -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();