diff --git a/src/generated/main/java/emu/grasscutter/net/proto/FriendBriefOuterClass.java b/src/generated/main/java/emu/grasscutter/net/proto/FriendBriefOuterClass.java index 7dde37122..0e1e0e2f3 100644 --- a/src/generated/main/java/emu/grasscutter/net/proto/FriendBriefOuterClass.java +++ b/src/generated/main/java/emu/grasscutter/net/proto/FriendBriefOuterClass.java @@ -217,16 +217,16 @@ public final class FriendBriefOuterClass { emu.grasscutter.net.proto.PlatformTypeOuterClass.PlatformType getPlatformType(); /** - * bool IEAHDCLDOEJ = 28; - * @return The iEAHDCLDOEJ. + * bool is_in_duel = 28; + * @return The isInDuel. */ - boolean getIEAHDCLDOEJ(); + boolean getIsInDuel(); /** - * bool BJFJJMGENCH = 29; - * @return The bJFJJMGENCH. + * bool is_duel_observable = 29; + * @return The isDuelObservable. */ - boolean getBJFJJMGENCH(); + boolean getIsDuelObservable(); } /** *
@@ -417,12 +417,12 @@ public final class FriendBriefOuterClass {
             }
             case 224: {
 
-              iEAHDCLDOEJ_ = input.readBool();
+              isInDuel_ = input.readBool();
               break;
             }
             case 232: {
 
-              bJFJJMGENCH_ = input.readBool();
+              isDuelObservable_ = input.readBool();
               break;
             }
             default: {
@@ -878,26 +878,26 @@ public final class FriendBriefOuterClass {
       return result == null ? emu.grasscutter.net.proto.PlatformTypeOuterClass.PlatformType.UNRECOGNIZED : result;
     }
 
-    public static final int IEAHDCLDOEJ_FIELD_NUMBER = 28;
-    private boolean iEAHDCLDOEJ_;
+    public static final int IS_IN_DUEL_FIELD_NUMBER = 28;
+    private boolean isInDuel_;
     /**
-     * bool IEAHDCLDOEJ = 28;
-     * @return The iEAHDCLDOEJ.
+     * bool is_in_duel = 28;
+     * @return The isInDuel.
      */
     @java.lang.Override
-    public boolean getIEAHDCLDOEJ() {
-      return iEAHDCLDOEJ_;
+    public boolean getIsInDuel() {
+      return isInDuel_;
     }
 
-    public static final int BJFJJMGENCH_FIELD_NUMBER = 29;
-    private boolean bJFJJMGENCH_;
+    public static final int IS_DUEL_OBSERVABLE_FIELD_NUMBER = 29;
+    private boolean isDuelObservable_;
     /**
-     * bool BJFJJMGENCH = 29;
-     * @return The bJFJJMGENCH.
+     * bool is_duel_observable = 29;
+     * @return The isDuelObservable.
      */
     @java.lang.Override
-    public boolean getBJFJJMGENCH() {
-      return bJFJJMGENCH_;
+    public boolean getIsDuelObservable() {
+      return isDuelObservable_;
     }
 
     private byte memoizedIsInitialized = -1;
@@ -980,11 +980,11 @@ public final class FriendBriefOuterClass {
       if (platformType_ != emu.grasscutter.net.proto.PlatformTypeOuterClass.PlatformType.PLATFORM_TYPE_EDITOR.getNumber()) {
         output.writeEnum(27, platformType_);
       }
-      if (iEAHDCLDOEJ_ != false) {
-        output.writeBool(28, iEAHDCLDOEJ_);
+      if (isInDuel_ != false) {
+        output.writeBool(28, isInDuel_);
       }
-      if (bJFJJMGENCH_ != false) {
-        output.writeBool(29, bJFJJMGENCH_);
+      if (isDuelObservable_ != false) {
+        output.writeBool(29, isDuelObservable_);
       }
       unknownFields.writeTo(output);
     }
@@ -1079,13 +1079,13 @@ public final class FriendBriefOuterClass {
         size += com.google.protobuf.CodedOutputStream
           .computeEnumSize(27, platformType_);
       }
-      if (iEAHDCLDOEJ_ != false) {
+      if (isInDuel_ != false) {
         size += com.google.protobuf.CodedOutputStream
-          .computeBoolSize(28, iEAHDCLDOEJ_);
+          .computeBoolSize(28, isInDuel_);
       }
-      if (bJFJJMGENCH_ != false) {
+      if (isDuelObservable_ != false) {
         size += com.google.protobuf.CodedOutputStream
-          .computeBoolSize(29, bJFJJMGENCH_);
+          .computeBoolSize(29, isDuelObservable_);
       }
       size += unknownFields.getSerializedSize();
       memoizedSize = size;
@@ -1146,10 +1146,10 @@ public final class FriendBriefOuterClass {
       if (getIsPsnSource()
           != other.getIsPsnSource()) return false;
       if (platformType_ != other.platformType_) return false;
-      if (getIEAHDCLDOEJ()
-          != other.getIEAHDCLDOEJ()) return false;
-      if (getBJFJJMGENCH()
-          != other.getBJFJJMGENCH()) return false;
+      if (getIsInDuel()
+          != other.getIsInDuel()) return false;
+      if (getIsDuelObservable()
+          != other.getIsDuelObservable()) return false;
       if (!unknownFields.equals(other.unknownFields)) return false;
       return true;
     }
@@ -1213,12 +1213,12 @@ public final class FriendBriefOuterClass {
           getIsPsnSource());
       hash = (37 * hash) + PLATFORM_TYPE_FIELD_NUMBER;
       hash = (53 * hash) + platformType_;
-      hash = (37 * hash) + IEAHDCLDOEJ_FIELD_NUMBER;
+      hash = (37 * hash) + IS_IN_DUEL_FIELD_NUMBER;
       hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(
-          getIEAHDCLDOEJ());
-      hash = (37 * hash) + BJFJJMGENCH_FIELD_NUMBER;
+          getIsInDuel());
+      hash = (37 * hash) + IS_DUEL_OBSERVABLE_FIELD_NUMBER;
       hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(
-          getBJFJJMGENCH());
+          getIsDuelObservable());
       hash = (29 * hash) + unknownFields.hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -1409,9 +1409,9 @@ public final class FriendBriefOuterClass {
 
         platformType_ = 0;
 
-        iEAHDCLDOEJ_ = false;
+        isInDuel_ = false;
 
-        bJFJJMGENCH_ = false;
+        isDuelObservable_ = false;
 
         return this;
       }
@@ -1474,8 +1474,8 @@ public final class FriendBriefOuterClass {
         result.isGameSource_ = isGameSource_;
         result.isPsnSource_ = isPsnSource_;
         result.platformType_ = platformType_;
-        result.iEAHDCLDOEJ_ = iEAHDCLDOEJ_;
-        result.bJFJJMGENCH_ = bJFJJMGENCH_;
+        result.isInDuel_ = isInDuel_;
+        result.isDuelObservable_ = isDuelObservable_;
         onBuilt();
         return result;
       }
@@ -1617,11 +1617,11 @@ public final class FriendBriefOuterClass {
         if (other.platformType_ != 0) {
           setPlatformTypeValue(other.getPlatformTypeValue());
         }
-        if (other.getIEAHDCLDOEJ() != false) {
-          setIEAHDCLDOEJ(other.getIEAHDCLDOEJ());
+        if (other.getIsInDuel() != false) {
+          setIsInDuel(other.getIsInDuel());
         }
-        if (other.getBJFJJMGENCH() != false) {
-          setBJFJJMGENCH(other.getBJFJJMGENCH());
+        if (other.getIsDuelObservable() != false) {
+          setIsDuelObservable(other.getIsDuelObservable());
         }
         this.mergeUnknownFields(other.unknownFields);
         onChanged();
@@ -2881,64 +2881,64 @@ public final class FriendBriefOuterClass {
         return this;
       }
 
-      private boolean iEAHDCLDOEJ_ ;
+      private boolean isInDuel_ ;
       /**
-       * bool IEAHDCLDOEJ = 28;
-       * @return The iEAHDCLDOEJ.
+       * bool is_in_duel = 28;
+       * @return The isInDuel.
        */
       @java.lang.Override
-      public boolean getIEAHDCLDOEJ() {
-        return iEAHDCLDOEJ_;
+      public boolean getIsInDuel() {
+        return isInDuel_;
       }
       /**
-       * bool IEAHDCLDOEJ = 28;
-       * @param value The iEAHDCLDOEJ to set.
+       * bool is_in_duel = 28;
+       * @param value The isInDuel to set.
        * @return This builder for chaining.
        */
-      public Builder setIEAHDCLDOEJ(boolean value) {
+      public Builder setIsInDuel(boolean value) {
         
-        iEAHDCLDOEJ_ = value;
+        isInDuel_ = value;
         onChanged();
         return this;
       }
       /**
-       * bool IEAHDCLDOEJ = 28;
+       * bool is_in_duel = 28;
        * @return This builder for chaining.
        */
-      public Builder clearIEAHDCLDOEJ() {
+      public Builder clearIsInDuel() {
         
-        iEAHDCLDOEJ_ = false;
+        isInDuel_ = false;
         onChanged();
         return this;
       }
 
-      private boolean bJFJJMGENCH_ ;
+      private boolean isDuelObservable_ ;
       /**
-       * bool BJFJJMGENCH = 29;
-       * @return The bJFJJMGENCH.
+       * bool is_duel_observable = 29;
+       * @return The isDuelObservable.
        */
       @java.lang.Override
-      public boolean getBJFJJMGENCH() {
-        return bJFJJMGENCH_;
+      public boolean getIsDuelObservable() {
+        return isDuelObservable_;
       }
       /**
-       * bool BJFJJMGENCH = 29;
-       * @param value The bJFJJMGENCH to set.
+       * bool is_duel_observable = 29;
+       * @param value The isDuelObservable to set.
        * @return This builder for chaining.
        */
-      public Builder setBJFJJMGENCH(boolean value) {
+      public Builder setIsDuelObservable(boolean value) {
         
-        bJFJJMGENCH_ = value;
+        isDuelObservable_ = value;
         onChanged();
         return this;
       }
       /**
-       * bool BJFJJMGENCH = 29;
+       * bool is_duel_observable = 29;
        * @return This builder for chaining.
        */
-      public Builder clearBJFJJMGENCH() {
+      public Builder clearIsDuelObservable() {
         
-        bJFJJMGENCH_ = false;
+        isDuelObservable_ = false;
         onChanged();
         return this;
       }
@@ -3012,7 +3012,7 @@ public final class FriendBriefOuterClass {
       "\n\021FriendBrief.proto\032\027FriendOnlineState.p" +
       "roto\032\032SocialShowAvatarInfo.proto\032\033Friend" +
       "EnterHomeOption.proto\032\024ProfilePicture.pr" +
-      "oto\032\022PlatformType.proto\"\210\005\n\013FriendBrief\022" +
+      "oto\032\022PlatformType.proto\"\216\005\n\013FriendBrief\022" +
       "\013\n\003uid\030\001 \001(\r\022\020\n\010nickname\030\002 \001(\t\022\r\n\005level\030" +
       "\003 \001(\r\022\021\n\tavatar_id\030\004 \001(\r\022\023\n\013world_level\030" +
       "\005 \001(\r\022\021\n\tsignature\030\006 \001(\t\022(\n\014online_state" +
@@ -3027,9 +3027,9 @@ public final class FriendBriefOuterClass {
       "\0162\026.FriendEnterHomeOption\022(\n\017profile_pic" +
       "ture\030\030 \001(\0132\017.ProfilePicture\022\026\n\016is_game_s" +
       "ource\030\031 \001(\010\022\025\n\ris_psn_source\030\032 \001(\010\022$\n\rpl" +
-      "atform_type\030\033 \001(\0162\r.PlatformType\022\023\n\013IEAH" +
-      "DCLDOEJ\030\034 \001(\010\022\023\n\013BJFJJMGENCH\030\035 \001(\010B\033\n\031em" +
-      "u.grasscutter.net.protob\006proto3"
+      "atform_type\030\033 \001(\0162\r.PlatformType\022\022\n\nis_i" +
+      "n_duel\030\034 \001(\010\022\032\n\022is_duel_observable\030\035 \001(\010" +
+      "B\033\n\031emu.grasscutter.net.protob\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -3045,7 +3045,7 @@ public final class FriendBriefOuterClass {
     internal_static_FriendBrief_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_FriendBrief_descriptor,
-        new java.lang.String[] { "Uid", "Nickname", "Level", "AvatarId", "WorldLevel", "Signature", "OnlineState", "Param", "IsMpModeAvailable", "OnlineId", "LastActiveTime", "NameCardId", "MpPlayerNum", "IsChatNoDisturb", "ChatSequence", "RemarkName", "ShowAvatarInfoList", "FriendEnterHomeOption", "ProfilePicture", "IsGameSource", "IsPsnSource", "PlatformType", "IEAHDCLDOEJ", "BJFJJMGENCH", });
+        new java.lang.String[] { "Uid", "Nickname", "Level", "AvatarId", "WorldLevel", "Signature", "OnlineState", "Param", "IsMpModeAvailable", "OnlineId", "LastActiveTime", "NameCardId", "MpPlayerNum", "IsChatNoDisturb", "ChatSequence", "RemarkName", "ShowAvatarInfoList", "FriendEnterHomeOption", "ProfilePicture", "IsGameSource", "IsPsnSource", "PlatformType", "IsInDuel", "IsDuelObservable", });
     emu.grasscutter.net.proto.FriendOnlineStateOuterClass.getDescriptor();
     emu.grasscutter.net.proto.SocialShowAvatarInfoOuterClass.getDescriptor();
     emu.grasscutter.net.proto.FriendEnterHomeOptionOuterClass.getDescriptor();
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/command/commands/GroupCommand.java b/src/main/java/emu/grasscutter/command/commands/GroupCommand.java
index 5bec40be1..74d94fb2d 100644
--- a/src/main/java/emu/grasscutter/command/commands/GroupCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/GroupCommand.java
@@ -10,7 +10,7 @@ import java.util.List;
 
 @Command(
         label = "group",
-        aliases = {"g"},
+        aliases = {"gr"},
         usage = {"(refresh) [] []"},
         permission = "player.group",
         permissionTargeted = "player.group.others")
diff --git a/src/main/java/emu/grasscutter/command/commands/SoundCommand.java b/src/main/java/emu/grasscutter/command/commands/SoundCommand.java
index f69db4e5e..ed36639e8 100644
--- a/src/main/java/emu/grasscutter/command/commands/SoundCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/SoundCommand.java
@@ -12,7 +12,7 @@ import lombok.val;
 
 @Command(
         label = "sound",
-        aliases = {"s", "audio"},
+        aliases = {"audio"},
         usage = {"[] []"},
         permission = "player.sound",
         permissionTargeted = "player.sound.others")
diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java
index 10c622904..e486c5655 100644
--- a/src/main/java/emu/grasscutter/data/GameData.java
+++ b/src/main/java/emu/grasscutter/data/GameData.java
@@ -4,33 +4,57 @@ import emu.grasscutter.Grasscutter;
 import emu.grasscutter.data.binout.*;
 import emu.grasscutter.data.binout.config.*;
 import emu.grasscutter.data.binout.routes.Route;
-import emu.grasscutter.data.custom.*;
+import emu.grasscutter.data.custom.TrialAvatarActivityCustomData;
+import emu.grasscutter.data.custom.TrialAvatarCustomData;
 import emu.grasscutter.data.excels.*;
-import emu.grasscutter.data.excels.achievement.*;
-import emu.grasscutter.data.excels.activity.*;
+import emu.grasscutter.data.excels.achievement.AchievementData;
+import emu.grasscutter.data.excels.achievement.AchievementGoalData;
+import emu.grasscutter.data.excels.activity.ActivityCondExcelConfigData;
+import emu.grasscutter.data.excels.activity.ActivityData;
+import emu.grasscutter.data.excels.activity.ActivityShopData;
+import emu.grasscutter.data.excels.activity.ActivityWatcherData;
 import emu.grasscutter.data.excels.avatar.*;
 import emu.grasscutter.data.excels.codex.*;
 import emu.grasscutter.data.excels.dungeon.*;
-import emu.grasscutter.data.excels.giving.*;
-import emu.grasscutter.data.excels.monster.*;
-import emu.grasscutter.data.excels.quest.*;
-import emu.grasscutter.data.excels.reliquary.*;
+import emu.grasscutter.data.excels.giving.GivingData;
+import emu.grasscutter.data.excels.giving.GivingGroupData;
+import emu.grasscutter.data.excels.monster.MonsterCurveData;
+import emu.grasscutter.data.excels.monster.MonsterData;
+import emu.grasscutter.data.excels.monster.MonsterDescribeData;
+import emu.grasscutter.data.excels.monster.MonsterSpecialNameData;
+import emu.grasscutter.data.excels.quest.QuestData;
+import emu.grasscutter.data.excels.quest.QuestGlobalVarData;
+import emu.grasscutter.data.excels.reliquary.ReliquaryAffixData;
+import emu.grasscutter.data.excels.reliquary.ReliquaryLevelData;
+import emu.grasscutter.data.excels.reliquary.ReliquaryMainPropData;
+import emu.grasscutter.data.excels.reliquary.ReliquarySetData;
 import emu.grasscutter.data.excels.scene.*;
-import emu.grasscutter.data.excels.tower.*;
+import emu.grasscutter.data.excels.tower.TowerFloorData;
+import emu.grasscutter.data.excels.tower.TowerLevelData;
+import emu.grasscutter.data.excels.tower.TowerScheduleData;
 import emu.grasscutter.data.excels.trial.*;
-import emu.grasscutter.data.excels.weapon.*;
-import emu.grasscutter.data.excels.world.*;
+import emu.grasscutter.data.excels.weapon.WeaponCurveData;
+import emu.grasscutter.data.excels.weapon.WeaponLevelData;
+import emu.grasscutter.data.excels.weapon.WeaponPromoteData;
+import emu.grasscutter.data.excels.world.WeatherData;
+import emu.grasscutter.data.excels.world.WorldAreaData;
+import emu.grasscutter.data.excels.world.WorldLevelData;
 import emu.grasscutter.data.server.*;
 import emu.grasscutter.game.dungeons.DungeonDropEntry;
-import emu.grasscutter.game.quest.*;
+import emu.grasscutter.game.quest.QuestEncryptionKey;
+import emu.grasscutter.game.quest.RewindData;
+import emu.grasscutter.game.quest.TeleportData;
 import emu.grasscutter.game.quest.enums.QuestCond;
 import emu.grasscutter.game.world.GroupReplacementData;
 import emu.grasscutter.utils.Utils;
 import it.unimi.dsi.fastutil.ints.*;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.val;
+
+import javax.annotation.Nullable;
 import java.lang.reflect.Field;
 import java.util.*;
-import javax.annotation.Nullable;
-import lombok.*;
 
 @SuppressWarnings({"unused", "MismatchedQueryAndUpdateOfCollection"})
 public final class GameData {
@@ -265,6 +289,10 @@ public final class GameData {
     private static final Int2ObjectMap homeWorldLevelDataMap =
             new Int2ObjectOpenHashMap<>();
 
+    @Getter
+    private static final Int2ObjectMap homeWorldNPCDataMap =
+            new Int2ObjectOpenHashMap<>();
+
     @Getter
     private static final Int2ObjectMap investigationMonsterDataMap =
             new Int2ObjectOpenHashMap<>();
diff --git a/src/main/java/emu/grasscutter/data/binout/HomeworldDefaultSaveData.java b/src/main/java/emu/grasscutter/data/binout/HomeworldDefaultSaveData.java
index 98ee7efa1..30f997e10 100644
--- a/src/main/java/emu/grasscutter/data/binout/HomeworldDefaultSaveData.java
+++ b/src/main/java/emu/grasscutter/data/binout/HomeworldDefaultSaveData.java
@@ -2,48 +2,49 @@ package emu.grasscutter.data.binout;
 
 import com.google.gson.annotations.SerializedName;
 import emu.grasscutter.game.world.Position;
-import java.util.List;
 import lombok.AccessLevel;
 import lombok.Data;
 import lombok.experimental.FieldDefaults;
 
+import java.util.List;
+
 @Data
 @FieldDefaults(level = AccessLevel.PRIVATE)
 public class HomeworldDefaultSaveData {
 
     @SerializedName(
-            value = "KFHBFNPDJBE",
-            alternate = {"PKACPHDGGEI", "AKOLOBLHDFK"})
+            value = "homeBlockLists",
+            alternate = {"PKACPHDGGEI", "AKOLOBLHDFK", "KFHBFNPDJBE"})
     List homeBlockLists;
 
     @SerializedName(
-            value = "IJNPADKGNKE",
-            alternate = {"MINCKHBNING", "MBICDPDEKDM"})
+            value = "bornPos",
+            alternate = {"MINCKHBNING", "MBICDPDEKDM", "IJNPADKGNKE"})
     Position bornPos;
 
     @SerializedName(
-            value = "IPIIGEMFLHK",
-            alternate = {"EJJIOJKFKCO"})
+            value = "bornRot",
+            alternate = {"EJJIOJKFKCO", "IPIIGEMFLHK"})
     Position bornRot;
 
     @SerializedName(
-            value = "HHOLBNPIHEM",
-            alternate = {"CJAKHCIFHNP"})
+            value = "djinPos",
+            alternate = {"CJAKHCIFHNP", "HHOLBNPIHEM"})
     Position djinPos;
 
     @SerializedName(
-            value = "KNHCJKHCOAN",
-            alternate = {"AMDNOHPGKMI"})
+            value = "mainhouse",
+            alternate = {"AMDNOHPGKMI", "KNHCJKHCOAN"})
     HomeFurniture mainhouse;
 
     @SerializedName(
-            value = "NIHOJFEKFPG",
-            alternate = {"BHCPEAOPIDC"})
+            value = "doorLists",
+            alternate = {"BHCPEAOPIDC", "NIHOJFEKFPG"})
     List doorLists;
 
     @SerializedName(
-            value = "EPGELGEFJFK",
-            alternate = {"AABEPENIFLN"})
+            value = "stairLists",
+            alternate = {"AABEPENIFLN", "EPGELGEFJFK"})
     List stairLists;
 
     @Data
@@ -51,18 +52,18 @@ public class HomeworldDefaultSaveData {
     public static class HomeBlock {
 
         @SerializedName(
-                value = "FGIJCELCGFI",
-                alternate = {"PGDPDIDJEEL", "ANICBLBOBKD"})
+                value = "blockId",
+                alternate = {"PGDPDIDJEEL", "ANICBLBOBKD", "FGIJCELCGFI"})
         int blockId;
 
         @SerializedName(
-                value = "BEAPOFELABD",
-                alternate = {"NCIMIKKFLOH"})
+                value = "furnitures",
+                alternate = {"NCIMIKKFLOH", "BEAPOFELABD"})
         List furnitures;
 
         @SerializedName(
-                value = "MLIODLGDFHJ",
-                alternate = {"GJGNLIINBGB"})
+                value = "persistentFurnitures",
+                alternate = {"GJGNLIINBGB", "MLIODLGDFHJ"})
         List persistentFurnitures;
     }
 
@@ -71,15 +72,18 @@ public class HomeworldDefaultSaveData {
     public static class HomeFurniture {
 
         @SerializedName(
-                value = "ENHNGKJBJAB",
-                alternate = {"KMAAJJHPNBA", "FFLCGFGGGND"})
+                value = "id",
+                alternate = {"KMAAJJHPNBA", "FFLCGFGGGND", "ENHNGKJBJAB"})
         int id;
 
         @SerializedName(
-                value = "NGIEEIOLPPO",
-                alternate = {"JFKAHNCPDME", "BPCGGBKIAMG"})
+                value = "pos",
+                alternate = {"JFKAHNCPDME", "BPCGGBKIAMG", "NGIEEIOLPPO"})
         Position pos;
-        // @SerializedName(value = "HEOCEHKEBFM", alternate = "LKCKOOGFDBM")
+
+        @SerializedName(
+                value = "rot",
+                alternate = {"LKCKOOGFDBM", "HEOCEHKEBFM"})
         Position rot;
     }
 }
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/data/excels/HomeWorldNPCData.java b/src/main/java/emu/grasscutter/data/excels/HomeWorldNPCData.java
new file mode 100644
index 000000000..6402d93f1
--- /dev/null
+++ b/src/main/java/emu/grasscutter/data/excels/HomeWorldNPCData.java
@@ -0,0 +1,35 @@
+package emu.grasscutter.data.excels;
+
+import com.google.gson.annotations.SerializedName;
+import emu.grasscutter.data.GameResource;
+import emu.grasscutter.data.ResourceType;
+import emu.grasscutter.game.inventory.ItemQuality;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.experimental.FieldDefaults;
+
+import java.util.List;
+
+@ResourceType(name = "HomeWorldNPCExcelConfigData.json")
+@Getter
+@FieldDefaults(level = AccessLevel.PRIVATE)
+public class HomeWorldNPCData extends GameResource {
+    int furnitureID;
+    int avatarID;
+    @SerializedName(value = "npcId", alternate = {"HDLJMOGHICL"})
+    int npcId;
+    @SerializedName(value = "talkIdList", alternate = {"CKMCLCNIBLD"})
+    List talkIdList;
+    @SerializedName(value = "isTalkRandomly", alternate = {"HPJMMEBNMAI"})
+    boolean isTalkRandomly;
+    @SerializedName(value = "npcQuality", alternate = {"BHJOIKFHIBD"})
+    ItemQuality npcQuality;
+    @SerializedName(value = "titleTextMapHash", alternate = {"GNMAIEGCFPO"})
+    long titleTextMapHash;
+    long descTextMapHash;
+
+    @Override
+    public int getId() {
+        return this.avatarID;
+    }
+}
diff --git a/src/main/java/emu/grasscutter/data/excels/ItemData.java b/src/main/java/emu/grasscutter/data/excels/ItemData.java
index 9ae04d278..1a10152a7 100644
--- a/src/main/java/emu/grasscutter/data/excels/ItemData.java
+++ b/src/main/java/emu/grasscutter/data/excels/ItemData.java
@@ -4,6 +4,7 @@ import com.google.gson.annotations.SerializedName;
 import emu.grasscutter.data.GameResource;
 import emu.grasscutter.data.ResourceType;
 import emu.grasscutter.data.common.ItemUseData;
+import emu.grasscutter.game.home.SpecialFurnitureType;
 import emu.grasscutter.game.inventory.EquipType;
 import emu.grasscutter.game.inventory.ItemType;
 import emu.grasscutter.game.inventory.MaterialType;
@@ -13,10 +14,11 @@ import emu.grasscutter.game.props.ItemUseOp;
 import emu.grasscutter.game.props.ItemUseTarget;
 import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
 import it.unimi.dsi.fastutil.ints.IntSet;
+import lombok.Getter;
+
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
-import lombok.Getter;
 
 @ResourceType(
         name = {
@@ -86,6 +88,7 @@ public class ItemData extends GameResource {
     private int comfort;
     private List furnType;
     private List furnitureGadgetID;
+    private SpecialFurnitureType specialFurnitureType = SpecialFurnitureType.NOT_SPECIAL;
 
     @SerializedName(
             value = "roomSceneId",
diff --git a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java
index b4a918b4e..49dfcfd6b 100644
--- a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java
+++ b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java
@@ -157,6 +157,13 @@ public class AvatarStorage extends BasePlayerManager implements Iterable
             // Add to avatar storage
             this.avatars.put(avatar.getAvatarId(), avatar);
             this.avatarsGuid.put(avatar.getGuid(), avatar);
+
+            // Set main character skill depot data, fixes loading with no element every login
+            if ((avatar.getAvatarId() == 10000007) || (avatar.getAvatarId() == 10000005)) {
+                avatar.setSkillDepot(skillDepot);
+                avatar.setSkillDepotData(skillDepot);
+                avatar.save();
+            }
         }
 
         this.setLoaded(true);
diff --git a/src/main/java/emu/grasscutter/game/friends/Friendship.java b/src/main/java/emu/grasscutter/game/friends/Friendship.java
index 5eb65a628..2282b7857 100644
--- a/src/main/java/emu/grasscutter/game/friends/Friendship.java
+++ b/src/main/java/emu/grasscutter/game/friends/Friendship.java
@@ -14,19 +14,24 @@ import org.bson.types.ObjectId;
 
 @Entity(value = "friendships", useDiscriminator = false)
 public class Friendship {
-    @Id private ObjectId id;
+    @Id
+    private ObjectId id;
 
-    @Transient private Player owner;
+    @Transient
+    private Player owner;
 
-    @Indexed private int ownerId;
-    @Indexed private int friendId;
+    @Indexed
+    private int ownerId;
+    @Indexed
+    private int friendId;
     private boolean isFriend;
     private int askerId;
 
     private PlayerProfile profile;
 
     @Deprecated // Morphia use only
-    public Friendship() {}
+    public Friendship() {
+    }
 
     public Friendship(Player owner, Player friend, Player asker) {
         this.setOwner(owner);
@@ -90,27 +95,28 @@ public class Friendship {
     }
 
     public FriendBrief toProto() {
-        FriendBrief proto =
-                FriendBrief.newBuilder()
-                        .setUid(getFriendProfile().getUid())
-                        .setNickname(getFriendProfile().getName())
-                        .setLevel(getFriendProfile().getPlayerLevel())
-                        .setProfilePicture(
-                                ProfilePicture.newBuilder().setAvatarId(getFriendProfile().getAvatarId()))
-                        .setWorldLevel(getFriendProfile().getWorldLevel())
-                        .setSignature(getFriendProfile().getSignature())
-                        .setOnlineState(
-                                getFriendProfile().isOnline()
-                                        ? FriendOnlineState.FRIEND_ONLINE_STATE_ONLINE
-                                        : FriendOnlineState.FRIEND_ONLINE_STATE_DISCONNECT)
-                        .setIsMpModeAvailable(true)
-                        .setLastActiveTime(getFriendProfile().getLastActiveTime())
-                        .setNameCardId(getFriendProfile().getNameCard())
-                        .setParam(getFriendProfile().getDaysSinceLogin())
-                        .setIsGameSource(true)
-                        .setPlatformType(PlatformTypeOuterClass.PlatformType.PLATFORM_TYPE_PC)
-                        .build();
+        var player = this.getFriendProfile().getPlayer(); // get latest player and sync.
 
-        return proto;
+        return FriendBrief.newBuilder()
+            .setUid(getFriendProfile().getUid())
+            .setNickname(getFriendProfile().getName())
+            .setLevel(getFriendProfile().getPlayerLevel())
+            .setProfilePicture(
+                ProfilePicture.newBuilder().setAvatarId(getFriendProfile().getAvatarId()))
+            .setWorldLevel(getFriendProfile().getWorldLevel())
+            .setSignature(getFriendProfile().getSignature())
+            .setOnlineState(
+                player != null && player.isOnline()
+                    ? FriendOnlineState.FRIEND_ONLINE_STATE_ONLINE
+                    : FriendOnlineState.FRIEND_ONLINE_STATE_DISCONNECT)
+            .setIsMpModeAvailable(true)
+            .setLastActiveTime(getFriendProfile().getLastActiveTime())
+            .setNameCardId(getFriendProfile().getNameCard())
+            .setParam(getFriendProfile().getDaysSinceLogin())
+            .setIsGameSource(true)
+            .setPlatformType(PlatformTypeOuterClass.PlatformType.PLATFORM_TYPE_PC)
+            .setIsInDuel(getFriendProfile().isInDuel())
+            .setIsDuelObservable(getFriendProfile().isDuelObservable())
+            .build();
     }
 }
diff --git a/src/main/java/emu/grasscutter/game/friends/PlayerProfile.java b/src/main/java/emu/grasscutter/game/friends/PlayerProfile.java
index 3f23aece8..d8106a7f8 100644
--- a/src/main/java/emu/grasscutter/game/friends/PlayerProfile.java
+++ b/src/main/java/emu/grasscutter/game/friends/PlayerProfile.java
@@ -2,14 +2,21 @@ package emu.grasscutter.game.friends;
 
 import dev.morphia.annotations.AlsoLoad;
 import dev.morphia.annotations.Entity;
+
+import emu.grasscutter.Grasscutter;
+
 import dev.morphia.annotations.Transient;
+import emu.grasscutter.game.home.GameHome;
+
 import emu.grasscutter.game.player.Player;
+import emu.grasscutter.net.proto.FriendEnterHomeOptionOuterClass;
 import emu.grasscutter.utils.Utils;
+import lombok.Getter;
+import org.jetbrains.annotations.Nullable;
 
 @Entity
+@Getter
 public class PlayerProfile {
-    @Transient private Player player;
-
     @AlsoLoad("id")
     private int uid;
 
@@ -17,12 +24,18 @@ public class PlayerProfile {
     private int avatarId;
     private String name;
     private String signature;
-    private int achievements;
 
     private int playerLevel;
     private int worldLevel;
     private int lastActiveTime;
 
+    private boolean isInDuel = false; // TODO: Implement duels. (TCG)
+    private boolean isDuelObservable = false; // TODO: Implement duels. (TCG)
+
+    @Getter
+    private int enterHomeOption;
+
+
     @Deprecated // Morphia only
     public PlayerProfile() {}
 
@@ -31,50 +44,13 @@ public class PlayerProfile {
         this.syncWithCharacter(player);
     }
 
-    public int getUid() {
-        return uid;
-    }
-
+    @Nullable
     public Player getPlayer() {
+        var player = Grasscutter.getGameServer().getPlayerByUid(this.getUid(), true);
+        this.syncWithCharacter(player);
         return player;
     }
 
-    public synchronized void setPlayer(Player player) {
-        this.player = player;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public int getNameCard() {
-        return nameCard;
-    }
-
-    public int getAvatarId() {
-        return avatarId;
-    }
-
-    public String getSignature() {
-        return signature;
-    }
-
-    public int getAchievements() {
-        return achievements;
-    }
-
-    public int getPlayerLevel() {
-        return playerLevel;
-    }
-
-    public int getWorldLevel() {
-        return worldLevel;
-    }
-
-    public int getLastActiveTime() {
-        return lastActiveTime;
-    }
-
     public void updateLastActiveTime() {
         this.lastActiveTime = Utils.getCurrentSeconds();
     }
@@ -83,10 +59,6 @@ public class PlayerProfile {
         return (int) Math.floor((Utils.getCurrentSeconds() - getLastActiveTime()) / 86400.0);
     }
 
-    public boolean isOnline() {
-        return this.getPlayer() != null;
-    }
-
     public void syncWithCharacter(Player player) {
         if (player == null) {
             return;
@@ -99,7 +71,7 @@ public class PlayerProfile {
         this.nameCard = player.getNameCardId();
         this.playerLevel = player.getLevel();
         this.worldLevel = player.getWorldLevel();
-        // this.achievements = 0;
+        this.enterHomeOption = player.tryGetHome().map(GameHome::getEnterHomeOption).orElse(FriendEnterHomeOptionOuterClass.FriendEnterHomeOption.FRIEND_ENTER_HOME_OPTION_REFUSE_VALUE);
         this.updateLastActiveTime();
     }
 }
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/HomeBlockItem.java b/src/main/java/emu/grasscutter/game/home/HomeBlockItem.java
index 22b0c6cf6..e2b1f0d8b 100644
--- a/src/main/java/emu/grasscutter/game/home/HomeBlockItem.java
+++ b/src/main/java/emu/grasscutter/game/home/HomeBlockItem.java
@@ -4,12 +4,15 @@ import dev.morphia.annotations.Entity;
 import dev.morphia.annotations.Id;
 import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
 import emu.grasscutter.net.proto.HomeBlockArrangementInfoOuterClass.HomeBlockArrangementInfo;
-import java.util.List;
 import lombok.AccessLevel;
 import lombok.Builder;
 import lombok.Data;
 import lombok.experimental.FieldDefaults;
 
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Stream;
+
 @Entity
 @Data
 @Builder(builderMethodName = "of")
@@ -77,6 +80,8 @@ public class HomeBlockItem {
                         .setIsUnlocked(unlocked)
                         .setComfortValue(calComfort());
 
+        this.reassignIfNull();
+
         this.deployFurnitureList.forEach(f -> proto.addDeployFurniureList(f.toProto()));
         this.persistentFurnitureList.forEach(f -> proto.addPersistentFurnitureList(f.toProto()));
         this.deployAnimalList.forEach(f -> proto.addDeployAnimalList(f.toProto()));
@@ -84,4 +89,26 @@ public class HomeBlockItem {
 
         return proto.build();
     }
+
+    // TODO add more types (farm field and suite)
+    public List getMarkPointProtoFactories() {
+        this.reassignIfNull();
+
+        return Stream.of(this.deployFurnitureList, this.persistentFurnitureList, this.deployNPCList).flatMap(Collection::stream).toList();
+    }
+
+    public void reassignIfNull() {
+        if (this.deployFurnitureList == null) {
+            this.deployFurnitureList = List.of();
+        }
+        if (this.persistentFurnitureList == null) {
+            this.persistentFurnitureList = List.of();
+        }
+        if (this.deployAnimalList == null) {
+            this.deployAnimalList = List.of();
+        }
+        if (this.deployNPCList == null) {
+            this.deployNPCList = List.of();
+        }
+    }
 }
diff --git a/src/main/java/emu/grasscutter/game/home/HomeFurnitureItem.java b/src/main/java/emu/grasscutter/game/home/HomeFurnitureItem.java
index a14b41833..11752f5e2 100644
--- a/src/main/java/emu/grasscutter/game/home/HomeFurnitureItem.java
+++ b/src/main/java/emu/grasscutter/game/home/HomeFurnitureItem.java
@@ -11,12 +11,24 @@ import lombok.AccessLevel;
 import lombok.Builder;
 import lombok.Data;
 import lombok.experimental.FieldDefaults;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Set;
+import java.util.stream.Collectors;
 
 @Entity
 @Data
 @FieldDefaults(level = AccessLevel.PRIVATE)
 @Builder(builderMethodName = "of")
-public class HomeFurnitureItem {
+public class HomeFurnitureItem implements HomeMarkPointProtoFactory {
+    public static final int PAIMON_FURNITURE_ID = 368134;
+    public static final int TELEPORT_FURNITURE_ID = 373501;
+    public static final Set APARTMENT_FURNITURE_ID_SET = GameData.getItemDataMap().values()
+        .stream()
+        .filter(itemData -> itemData.getSpecialFurnitureType() == SpecialFurnitureType.Apartment)
+        .map(ItemData::getId)
+        .collect(Collectors.toUnmodifiableSet());
+
     int furnitureId;
     int guid;
     int parentFurnitureIndex;
@@ -41,7 +53,7 @@ public class HomeFurnitureItem {
                 .furnitureId(homeFurniture.getId())
                 .parentFurnitureIndex(1)
                 .spawnPos(homeFurniture.getPos() == null ? new Position() : homeFurniture.getPos())
-                .spawnRot(homeFurniture.getRot() == null ? new Position() : homeFurniture.getRot())
+                .spawnRot(new Position())
                 .build();
     }
 
@@ -56,17 +68,6 @@ public class HomeFurnitureItem {
                 .build();
     }
 
-    public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto(
-            int type) {
-        return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
-                .setFurnitureId(furnitureId)
-                .setGuid(guid)
-                .setFurnitureType(type)
-                .setPos(spawnPos.toProto())
-                // TODO NPC and farm
-                .build();
-    }
-
     public ItemData getAsItem() {
         return GameData.getItemDataMap().get(this.furnitureId);
     }
@@ -79,4 +80,29 @@ public class HomeFurnitureItem {
         }
         return item.getComfort();
     }
+
+    @Nullable
+    @Override
+    public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto() {
+        var type = this.adjustByFurnitureId();
+        if (type == SpecialFurnitureType.NOT_SPECIAL) {
+            return null;
+        }
+
+        return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
+            .setFurnitureId(this.furnitureId)
+            .setFurnitureType(type.getValue())
+            .setPos(this.spawnPos.toProto())
+            .setGuid(this.guid)
+            .build();
+    }
+
+    @Override
+    public SpecialFurnitureType adjustByFurnitureId() {
+        return switch (this.furnitureId) {
+            case PAIMON_FURNITURE_ID -> SpecialFurnitureType.Paimon;
+            case TELEPORT_FURNITURE_ID -> SpecialFurnitureType.TeleportPoint;
+            default -> APARTMENT_FURNITURE_ID_SET.contains(this.furnitureId) ? SpecialFurnitureType.Apartment : SpecialFurnitureType.NOT_SPECIAL;
+        };
+    }
 }
diff --git a/src/main/java/emu/grasscutter/game/home/HomeMarkPointProtoFactory.java b/src/main/java/emu/grasscutter/game/home/HomeMarkPointProtoFactory.java
new file mode 100644
index 000000000..a1b7b33df
--- /dev/null
+++ b/src/main/java/emu/grasscutter/game/home/HomeMarkPointProtoFactory.java
@@ -0,0 +1,21 @@
+package emu.grasscutter.game.home;
+
+import emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass;
+import org.jetbrains.annotations.Nullable;
+
+public interface HomeMarkPointProtoFactory {
+    @Nullable
+    HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto();
+
+    default SpecialFurnitureType adjustByFurnitureId() {
+        return this.getType();
+    }
+
+    default SpecialFurnitureType getType() {
+        return SpecialFurnitureType.NOT_SPECIAL;
+    }
+
+    default boolean isProtoConvertible() {
+        return this.adjustByFurnitureId() != SpecialFurnitureType.NOT_SPECIAL;
+    }
+}
diff --git a/src/main/java/emu/grasscutter/game/home/HomeNPCItem.java b/src/main/java/emu/grasscutter/game/home/HomeNPCItem.java
index cce6fa055..129b60248 100644
--- a/src/main/java/emu/grasscutter/game/home/HomeNPCItem.java
+++ b/src/main/java/emu/grasscutter/game/home/HomeNPCItem.java
@@ -1,18 +1,23 @@
 package emu.grasscutter.game.home;
 
 import dev.morphia.annotations.Entity;
+import emu.grasscutter.data.GameData;
 import emu.grasscutter.game.world.Position;
+import emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass;
+import emu.grasscutter.net.proto.HomeMarkPointNPCDataOuterClass;
 import emu.grasscutter.net.proto.HomeNpcDataOuterClass;
 import lombok.AccessLevel;
 import lombok.Builder;
 import lombok.Data;
 import lombok.experimental.FieldDefaults;
+import org.jetbrains.annotations.Nullable;
 
 @Entity
 @Data
 @FieldDefaults(level = AccessLevel.PRIVATE)
 @Builder(builderMethodName = "of")
-public class HomeNPCItem {
+public class HomeNPCItem implements HomeMarkPointProtoFactory {
+    transient int furnitureId;
     int avatarId;
     Position spawnPos;
     Position spawnRot;
@@ -20,19 +25,52 @@ public class HomeNPCItem {
 
     public static HomeNPCItem parseFrom(HomeNpcDataOuterClass.HomeNpcData homeNpcData) {
         return HomeNPCItem.of()
-                .avatarId(homeNpcData.getAvatarId())
-                .spawnPos(new Position(homeNpcData.getSpawnPos()))
-                .spawnRot(new Position(homeNpcData.getSpawnRot()))
-                .costumeId(homeNpcData.getCostumeId())
-                .build();
+            .avatarId(homeNpcData.getAvatarId())
+            .spawnPos(new Position(homeNpcData.getSpawnPos()))
+            .spawnRot(new Position(homeNpcData.getSpawnRot()))
+            .costumeId(homeNpcData.getCostumeId())
+            .build();
     }
 
     public HomeNpcDataOuterClass.HomeNpcData toProto() {
         return HomeNpcDataOuterClass.HomeNpcData.newBuilder()
-                .setAvatarId(avatarId)
-                .setSpawnPos(spawnPos.toProto())
-                .setSpawnRot(spawnRot.toProto())
-                .setCostumeId(costumeId)
-                .build();
+            .setAvatarId(avatarId)
+            .setSpawnPos(spawnPos.toProto())
+            .setSpawnRot(spawnRot.toProto())
+            .setCostumeId(costumeId)
+            .build();
+    }
+
+    public int getFurnitureId() {
+        if (this.furnitureId == 0) {
+            var data = GameData.getHomeWorldNPCDataMap().get(this.avatarId);
+            this.furnitureId = data == null ? -1 : data.getFurnitureID();
+        }
+
+        return this.furnitureId;
+    }
+
+    @Nullable
+    @Override
+    public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto() {
+        return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
+            .setFurnitureId(this.getFurnitureId())
+            .setFurnitureType(this.getType().getValue())
+            .setPos(this.spawnPos.toProto())
+            .setNpcData(HomeMarkPointNPCDataOuterClass.HomeMarkPointNPCData.newBuilder()
+                .setAvatarId(this.avatarId)
+                .setCostumeId(this.costumeId)
+                .build())
+            .build();
+    }
+
+    @Override
+    public SpecialFurnitureType getType() {
+        return SpecialFurnitureType.NPC;
+    }
+
+    @Override
+    public boolean isProtoConvertible() {
+        return this.getFurnitureId() > 0;
     }
 }
diff --git a/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java b/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java
index d8e22dc4b..c3c38ef71 100644
--- a/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java
+++ b/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java
@@ -6,13 +6,14 @@ import emu.grasscutter.Grasscutter;
 import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
 import emu.grasscutter.game.world.Position;
 import emu.grasscutter.net.proto.HomeSceneArrangementInfoOuterClass.HomeSceneArrangementInfo;
-import java.util.Map;
-import java.util.stream.Collectors;
 import lombok.AccessLevel;
 import lombok.Builder;
 import lombok.Data;
 import lombok.experimental.FieldDefaults;
 
+import java.util.Map;
+import java.util.stream.Collectors;
+
 @Entity
 @Data
 @Builder(builderMethodName = "of")
@@ -64,12 +65,16 @@ public class HomeSceneItem {
     }
 
     public int getRoomSceneId() {
-        if (mainHouse == null || mainHouse.getAsItem() == null) {
+        if (this.isRoom()) {
             return 0;
         }
         return mainHouse.getAsItem().getRoomSceneId();
     }
 
+    public boolean isRoom() {
+        return mainHouse == null || mainHouse.getAsItem() == null;
+    }
+
     public int calComfort() {
         return this.blockItems.values().stream().mapToInt(HomeBlockItem::calComfort).sum();
     }
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/home/SpecialFurnitureType.java b/src/main/java/emu/grasscutter/game/home/SpecialFurnitureType.java
new file mode 100644
index 000000000..d2368838a
--- /dev/null
+++ b/src/main/java/emu/grasscutter/game/home/SpecialFurnitureType.java
@@ -0,0 +1,20 @@
+package emu.grasscutter.game.home;
+
+import lombok.Getter;
+
+@Getter
+public enum SpecialFurnitureType {
+    NOT_SPECIAL(-1),
+    FarmField(2),
+    TeleportPoint(3),
+    NPC(5),
+    Apartment(6),
+    FurnitureSuite(7),
+    Paimon(8);
+
+    private final int value;
+
+    SpecialFurnitureType(int value) {
+        this.value = value;
+    }
+}
diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java
index 8b587be4a..95303eaef 100644
--- a/src/main/java/emu/grasscutter/game/player/Player.java
+++ b/src/main/java/emu/grasscutter/game/player/Player.java
@@ -17,15 +17,26 @@ import emu.grasscutter.game.entity.GameEntity;
 import emu.grasscutter.game.expedition.ExpeditionInfo;
 import emu.grasscutter.game.friends.*;
 import emu.grasscutter.game.gacha.PlayerGachaInfo;
+import emu.grasscutter.game.home.EnterHomeRequest;
 import emu.grasscutter.game.home.GameHome;
-import emu.grasscutter.game.inventory.*;
-import emu.grasscutter.game.mail.*;
-import emu.grasscutter.game.managers.*;
-import emu.grasscutter.game.managers.cooking.*;
+import emu.grasscutter.game.home.HomeWorld;
+import emu.grasscutter.game.inventory.GameItem;
+import emu.grasscutter.game.inventory.Inventory;
+import emu.grasscutter.game.mail.Mail;
+import emu.grasscutter.game.mail.MailHandler;
+import emu.grasscutter.game.managers.FurnitureManager;
+import emu.grasscutter.game.managers.ResinManager;
+import emu.grasscutter.game.managers.SatiationManager;
+import emu.grasscutter.game.managers.SotSManager;
+import emu.grasscutter.game.managers.cooking.ActiveCookCompoundData;
+import emu.grasscutter.game.managers.cooking.CookingCompoundManager;
+import emu.grasscutter.game.managers.cooking.CookingManager;
 import emu.grasscutter.game.managers.deforestation.DeforestationManager;
 import emu.grasscutter.game.managers.energy.EnergyManager;
-import emu.grasscutter.game.managers.forging.*;
-import emu.grasscutter.game.managers.mapmark.*;
+import emu.grasscutter.game.managers.forging.ActiveForgeData;
+import emu.grasscutter.game.managers.forging.ForgingManager;
+import emu.grasscutter.game.managers.mapmark.MapMark;
+import emu.grasscutter.game.managers.mapmark.MapMarksManager;
 import emu.grasscutter.game.managers.stamina.StaminaManager;
 import emu.grasscutter.game.props.*;
 import emu.grasscutter.game.quest.QuestManager;
@@ -47,12 +58,14 @@ import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
 import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
 import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
 import emu.grasscutter.plugin.api.PlayerHook;
+import emu.grasscutter.scripts.ScriptLoader;
 import emu.grasscutter.scripts.data.SceneRegion;
 import emu.grasscutter.server.event.player.*;
 import emu.grasscutter.server.game.*;
 import emu.grasscutter.server.game.GameSession.SessionState;
 import emu.grasscutter.server.packet.send.*;
-import emu.grasscutter.utils.*;
+import emu.grasscutter.utils.DispatchUtils;
+import emu.grasscutter.utils.Utils;
 import emu.grasscutter.utils.helpers.DateHelper;
 import emu.grasscutter.utils.objects.FieldFetch;
 import it.unimi.dsi.fastutil.ints.*;
@@ -79,6 +92,8 @@ public class Player implements PlayerHook, FieldFetch {
     @Getter private int nameCardId = 210001;
     @Getter private Position position;
     @Getter @Setter private Position prevPos;
+    @Getter @Setter private Position prevPosForHome;
+    @Getter @Setter private int prevScene;
     @Getter private Position rotation;
     @Getter private PlayerBirthday birthday;
     @Getter private PlayerCodex codex;
@@ -87,6 +102,7 @@ public class Player implements PlayerHook, FieldFetch {
     @Getter @Setter private List 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;
@@ -119,6 +135,8 @@ public class Player implements PlayerHook, FieldFetch {
     @Transient private long nextGuid = 0;
     @Transient @Getter @Setter private int peerId;
     @Transient private World world;  // Synchronized getter and setter
+    @Transient @Getter @Setter private HomeWorld curHomeWorld;
+    @Transient @Getter @Setter private boolean hasSentInitPacketInHome;
     @Transient private Scene scene;  // Synchronized getter and setter
     @Transient @Getter private int weatherId = 0;
     @Transient @Getter private ClimateType climate = ClimateType.CLIMATE_SUNNY;
@@ -173,6 +191,7 @@ public class Player implements PlayerHook, FieldFetch {
     @Transient @Getter @Setter private SceneLoadState sceneLoadState = SceneLoadState.NONE;
     @Transient private boolean hasSentLoginPackets;
     @Transient private long nextSendPlayerLocTime = 0;
+    @Getter private transient final Int2ObjectMap enterHomeRequests;
 
     private transient final Int2ObjectMap coopRequests;  // Synchronized getter
     @Getter private transient final Queue attackResults;
@@ -209,6 +228,7 @@ public class Player implements PlayerHook, FieldFetch {
         this.buffManager = new PlayerBuffManager(this);
         this.position = new Position(GameConstants.START_POSITION);
         this.prevPos = new Position();
+        this.prevPosForHome = Position.ZERO;
         this.rotation = new Position(0, 307, 0);
         this.sceneId = 3;
         this.regionId = 1;
@@ -245,6 +265,7 @@ public class Player implements PlayerHook, FieldFetch {
 
         this.attackResults = new LinkedBlockingQueue<>();
         this.coopRequests = new Int2ObjectOpenHashMap<>();
+        this.enterHomeRequests = new Int2ObjectOpenHashMap<>();
         this.combatInvokeHandler = new InvokeHandler(PacketCombatInvocationsNotify.class);
         this.abilityInvokeHandler = new InvokeHandler(PacketAbilityInvocationsNotify.class);
         this.clientAbilityInitFinishHandler = new InvokeHandler(PacketClientAbilityInitFinishNotify.class);
@@ -465,6 +486,18 @@ public class Player implements PlayerHook, FieldFetch {
         this.seenRealmList.add(seenId);
     }
 
+    public Optional tryGetHome() {
+        if (this.isOnline()) {
+            return Optional.ofNullable(this.home);
+        }
+
+        if (GameHome.doesHomeExist(this.getUid())) {
+            this.home = GameHome.getByUid(this.getUid());
+        }
+
+        return Optional.ofNullable(this.home);
+    }
+
     public int getExpeditionLimit() {
         final int CONST_VALUE_EXPEDITION_INIT_LIMIT = 2;  // TODO: pull from ConstValueExcelConfigData.json
         int expeditionLimit = CONST_VALUE_EXPEDITION_INIT_LIMIT;
@@ -687,7 +720,7 @@ public class Player implements PlayerHook, FieldFetch {
         this.getQuestManager().forEachActiveQuest(quest -> {
             if (quest.getTriggerData() != null &&
                 quest.getTriggers().containsKey(enterRegionName) &&
-                    region.getGroupId() == quest.getTriggerData().get(enterRegionName).getGroupId()) {
+                region.getGroupId() == quest.getTriggerData().get(enterRegionName).getGroupId()) {
                 // If trigger hasn't been fired yet
                 if (!Boolean.TRUE.equals(quest.getTriggers().put(enterRegionName, true))) {
                     this.getSession().send(new PacketServerCondMeetQuestListUpdateNotify());
@@ -1175,6 +1208,21 @@ public class Player implements PlayerHook, FieldFetch {
         return true;
     }
 
+    private boolean expireEnterHomeRequest(EnterHomeRequest req) {
+        return this.expireEnterHomeRequest(req, false);
+    }
+
+    private boolean expireEnterHomeRequest(EnterHomeRequest req, boolean force) {
+        if (!req.isExpired() && !force) return false;
+        req.getRequester().sendPacket(new PacketPlayerApplyEnterHomeResultNotify(
+            this.getUid(),
+            this.getNickname(),
+            false,
+            PlayerApplyEnterHomeResultNotifyOuterClass.PlayerApplyEnterHomeResultNotify.Reason.SYSTEM_JUDGE));
+        req.getRequester().sendPacket(new PacketTryEnterHomeRsp());
+        return true;
+    }
+
     public synchronized void onTick() {
         // Check ping
         if (this.getLastPingTime() > System.currentTimeMillis() + 60000) {
@@ -1183,6 +1231,8 @@ public class Player implements PlayerHook, FieldFetch {
         }
         // Check co-op requests
         this.getCoopRequests().values().removeIf(this::expireCoopRequest);
+        // Check enter-home requests
+        this.getEnterHomeRequests().values().removeIf(this::expireEnterHomeRequest);
         // Handle buff
         this.getBuffManager().onTick();
         // Ping
@@ -1339,6 +1389,16 @@ public class Player implements PlayerHook, FieldFetch {
         }
         */
 
+
+        if (GameHome.HOME_SCENE_IDS.contains(this.getSceneId())) {
+            this.setSceneId(this.prevScene <= 0 ? 3 : this.prevScene); // if the player in home, make the player go back.
+            var pos = this.getPrevPosForHome();
+            if (pos.equals(Position.ZERO)) {
+                pos = ScriptLoader.getSceneMeta(this.getSceneId()).config.born_pos;
+            }
+            this.position.set(pos);
+        }
+
         // Create world
         World world = new World(this);
         world.addPlayer(this);
@@ -1387,7 +1447,10 @@ public class Player implements PlayerHook, FieldFetch {
 
         this.furnitureManager.onLogin();
         // Home
-        home = GameHome.getByUid(getUid());
+        var homeWorld = this.getServer().getHomeWorldOrCreate(this);
+        homeWorld.setHost(this); // synchronize player object if homeWorld already exists in the server.
+        this.home = homeWorld.getHome();
+        this.setCurHomeWorld(homeWorld);
         home.onOwnerLogin(this);
         // Activity
         this.activityManager = new ActivityManager(this);
@@ -1411,7 +1474,6 @@ public class Player implements PlayerHook, FieldFetch {
 
         // register
         getServer().registerPlayer(this);
-        getProfile().setPlayer(this); // Set online
     }
 
     public void onLogout() {
@@ -1432,9 +1494,10 @@ public class Player implements PlayerHook, FieldFetch {
 
             // Status stuff
             this.getProfile().syncWithCharacter(this);
-            this.getProfile().setPlayer(null); // Set offline
 
             this.getCoopRequests().clear();
+            this.getEnterHomeRequests().values().forEach(req -> this.expireEnterHomeRequest(req, true));
+            this.getEnterHomeRequests().clear();
 
             // Save to db
             this.save();
diff --git a/src/main/java/emu/grasscutter/game/player/TeamManager.java b/src/main/java/emu/grasscutter/game/player/TeamManager.java
index a2d9fa34a..159eaa699 100644
--- a/src/main/java/emu/grasscutter/game/player/TeamManager.java
+++ b/src/main/java/emu/grasscutter/game/player/TeamManager.java
@@ -1,31 +1,47 @@
 package emu.grasscutter.game.player;
 
-import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
-
-import dev.morphia.annotations.*;
-import emu.grasscutter.*;
+import dev.morphia.annotations.Entity;
+import dev.morphia.annotations.Transient;
+import emu.grasscutter.GameConstants;
+import emu.grasscutter.Grasscutter;
 import emu.grasscutter.data.GameData;
 import emu.grasscutter.data.excels.avatar.AvatarSkillDepotData;
 import emu.grasscutter.game.avatar.Avatar;
-import emu.grasscutter.game.entity.*;
-import emu.grasscutter.game.props.*;
-import emu.grasscutter.game.world.*;
-import emu.grasscutter.net.packet.*;
-import emu.grasscutter.net.proto.*;
+import emu.grasscutter.game.entity.EntityAvatar;
+import emu.grasscutter.game.entity.EntityBaseGadget;
+import emu.grasscutter.game.entity.EntityTeam;
+import emu.grasscutter.game.props.ElementType;
+import emu.grasscutter.game.props.EnterReason;
+import emu.grasscutter.game.props.FightProperty;
+import emu.grasscutter.game.world.Position;
+import emu.grasscutter.game.world.Scene;
+import emu.grasscutter.game.world.World;
+import emu.grasscutter.net.packet.BasePacket;
+import emu.grasscutter.net.packet.PacketOpcodes;
+import emu.grasscutter.net.proto.AbilityControlBlockOuterClass;
+import emu.grasscutter.net.proto.AbilityEmbryoOuterClass;
 import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
 import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
 import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType;
 import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
 import emu.grasscutter.net.proto.TrialAvatarGrantRecordOuterClass.TrialAvatarGrantRecord.GrantReason;
+import emu.grasscutter.net.proto.VisionTypeOuterClass;
 import emu.grasscutter.server.event.entity.EntityCreationEvent;
 import emu.grasscutter.server.event.player.*;
 import emu.grasscutter.server.packet.send.*;
 import emu.grasscutter.utils.Utils;
-import it.unimi.dsi.fastutil.ints.*;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
+import it.unimi.dsi.fastutil.ints.IntSet;
 import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.val;
+
 import java.util.*;
 import java.util.stream.Stream;
-import lombok.*;
+
+import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
 
 @Entity
 public final class TeamManager extends BasePlayerDataManager {
@@ -350,8 +366,8 @@ public final class TeamManager extends BasePlayerDataManager {
     /** Updates all properties of the active team. */
     public void updateTeamProperties() {
         this.updateTeamResonances(); // Update team resonances.
-        this.getPlayer()
-                .sendPacket(new PacketSceneTeamUpdateNotify(this.getPlayer())); // Notify the player.
+        this.getWorld()
+                .broadcastPacket(new PacketSceneTeamUpdateNotify(this.getPlayer())); // Notify the all players in the world.
 
         // Skill charges packet - Yes, this is official server behavior as of 2.6.0
         this.getActiveTeam().stream()
diff --git a/src/main/java/emu/grasscutter/game/props/ElementType.java b/src/main/java/emu/grasscutter/game/props/ElementType.java
index 5b7bcc6a6..805fa5cbe 100644
--- a/src/main/java/emu/grasscutter/game/props/ElementType.java
+++ b/src/main/java/emu/grasscutter/game/props/ElementType.java
@@ -10,7 +10,10 @@ import java.util.stream.Stream;
 import lombok.Getter;
 
 public enum ElementType implements IntValueEnum {
-    None(0, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
+    None(
+            0,
+            FightProperty.FIGHT_PROP_CUR_WIND_ENERGY,
+            FightProperty.FIGHT_PROP_MAX_WIND_ENERGY),
     Fire(
             1,
             FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY,
@@ -90,7 +93,7 @@ public enum ElementType implements IntValueEnum {
     @Getter private final int configHash;
 
     ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp) {
-        this(value, curEnergyProp, maxEnergyProp, 0, null, 1);
+        this(value, curEnergyProp, maxEnergyProp, 0, null, 0);
     }
 
     ElementType(
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 bc2f2b26f..9521ef212 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,32 +12,44 @@ import emu.grasscutter.data.excels.scene.SceneData;
 import emu.grasscutter.data.excels.world.WorldLevelData;
 import emu.grasscutter.data.server.Grid;
 import emu.grasscutter.game.avatar.Avatar;
-import emu.grasscutter.game.dungeons.*;
+import emu.grasscutter.game.dungeons.DungeonManager;
+import emu.grasscutter.game.dungeons.DungeonSettleListener;
 import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
 import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
 import emu.grasscutter.game.entity.*;
 import emu.grasscutter.game.entity.gadget.GadgetWorktop;
 import emu.grasscutter.game.inventory.GameItem;
 import emu.grasscutter.game.managers.blossom.BlossomManager;
-import emu.grasscutter.game.player.*;
+import emu.grasscutter.game.player.Player;
+import emu.grasscutter.game.player.TeamInfo;
 import emu.grasscutter.game.props.*;
 import emu.grasscutter.game.quest.QuestGroupSuite;
 import emu.grasscutter.game.world.data.TeleportProperties;
 import emu.grasscutter.net.packet.BasePacket;
-import emu.grasscutter.net.proto.*;
 import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
+import emu.grasscutter.net.proto.EnterTypeOuterClass;
+import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass;
 import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
-import emu.grasscutter.scripts.*;
+import emu.grasscutter.scripts.SceneIndexManager;
+import emu.grasscutter.scripts.SceneScriptManager;
 import emu.grasscutter.scripts.constants.EventType;
-import emu.grasscutter.scripts.data.*;
+import emu.grasscutter.scripts.data.SceneBlock;
+import emu.grasscutter.scripts.data.SceneGroup;
+import emu.grasscutter.scripts.data.ScriptArgs;
 import emu.grasscutter.server.event.entity.EntityCreationEvent;
 import emu.grasscutter.server.event.player.PlayerTeleportEvent;
 import emu.grasscutter.server.packet.send.*;
 import emu.grasscutter.server.scheduler.ServerTaskScheduler;
 import emu.grasscutter.utils.objects.KahnsSort;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.val;
+
+import javax.annotation.Nullable;
 import java.util.*;
-import java.util.concurrent.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.stream.Collectors;
 import javax.annotation.Nullable;
 import lombok.*;
@@ -259,6 +272,13 @@ public final class Scene {
             this.removeEntity(gadget);
         }
 
+        // Remove player widget gadgets
+        this.getEntities().values().stream()
+            .filter(gameEntity -> gameEntity instanceof EntityVehicle)
+            .map(gameEntity -> (EntityVehicle) gameEntity)
+            .filter(entityVehicle -> entityVehicle.getOwner().equals(player))
+            .forEach(entityVehicle -> this.removeEntity(entityVehicle, VisionType.VISION_TYPE_REMOVE));
+
         // Deregister scene if not in use
         if (this.getPlayerCount() <= 0 && !this.dontDestroyWhenEmpty) {
             this.getScriptManager().onDestroy();
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/http/dispatch/RegionHandler.java b/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java
index 1b6a9561e..d6b3f6c4f 100644
--- a/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java
+++ b/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java
@@ -267,7 +267,7 @@ public final class RegionHandler implements Router {
                                     .setRegionInfo(RegionInfo.newBuilder())
                                     .setStopServer(
                                             StopServerInfo.newBuilder()
-                                                    .setUrl("https://discord.gg/grasscutters")
+                                                    .setUrl("https://discord.gg/T5vZU6UyeG")
                                                     .setStopBeginTime((int) Instant.now().getEpochSecond())
                                                     .setStopEndTime((int) Instant.now().getEpochSecond() + 1)
                                                     .setContentMsg(
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/HandlerEvtAvatarEnterFocusNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtAvatarEnterFocusNotify.java
new file mode 100644
index 000000000..8429e03d3
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtAvatarEnterFocusNotify.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.EvtAvatarEnterFocusNotifyOuterClass;
+import emu.grasscutter.server.game.GameSession;
+import emu.grasscutter.server.packet.send.PacketEvtAvatarEnterFocusNotify;
+
+@Opcodes(PacketOpcodes.EvtAvatarEnterFocusNotify)
+public class HandlerEvtAvatarEnterFocusNotify extends PacketHandler {
+    @Override
+    public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
+        session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtAvatarEnterFocusNotify(EvtAvatarEnterFocusNotifyOuterClass.EvtAvatarEnterFocusNotify.parseFrom(payload)));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtAvatarExitFocusNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtAvatarExitFocusNotify.java
new file mode 100644
index 000000000..d5d6102be
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtAvatarExitFocusNotify.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.EvtAvatarExitFocusNotifyOuterClass;
+import emu.grasscutter.server.game.GameSession;
+import emu.grasscutter.server.packet.send.PacketEvtAvatarExitFocusNotify;
+
+@Opcodes(PacketOpcodes.EvtAvatarExitFocusNotify)
+public class HandlerEvtAvatarExitFocusNotify extends PacketHandler {
+    @Override
+    public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
+        session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtAvatarExitFocusNotify(EvtAvatarExitFocusNotifyOuterClass.EvtAvatarExitFocusNotify.parseFrom(payload)));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtAvatarUpdateFocusNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtAvatarUpdateFocusNotify.java
new file mode 100644
index 000000000..0bc55b5ed
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtAvatarUpdateFocusNotify.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.EvtAvatarUpdateFocusNotifyOuterClass;
+import emu.grasscutter.server.game.GameSession;
+import emu.grasscutter.server.packet.send.PacketEvtAvatarUpdateFocusNotify;
+
+@Opcodes(PacketOpcodes.EvtAvatarUpdateFocusNotify)
+public class HandlerEvtAvatarUpdateFocusNotify extends PacketHandler {
+    @Override
+    public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
+        session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtAvatarUpdateFocusNotify(EvtAvatarUpdateFocusNotifyOuterClass.EvtAvatarUpdateFocusNotify.parseFrom(payload)));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtBulletDeactiveNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtBulletDeactiveNotify.java
new file mode 100644
index 000000000..119f5bf04
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtBulletDeactiveNotify.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.EvtBulletDeactiveNotifyOuterClass;
+import emu.grasscutter.server.game.GameSession;
+import emu.grasscutter.server.packet.send.PacketEvtBulletDeactiveNotify;
+
+@Opcodes(PacketOpcodes.EvtBulletDeactiveNotify)
+public class HandlerEvtBulletDeactiveNotify extends PacketHandler {
+    @Override
+    public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
+        session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtBulletDeactiveNotify(EvtBulletDeactiveNotifyOuterClass.EvtBulletDeactiveNotify.parseFrom(payload)));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtBulletHitNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtBulletHitNotify.java
new file mode 100644
index 000000000..98ae79dfc
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtBulletHitNotify.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.EvtBulletHitNotifyOuterClass;
+import emu.grasscutter.server.game.GameSession;
+import emu.grasscutter.server.packet.send.PacketEvtBulletHitNotify;
+
+@Opcodes(PacketOpcodes.EvtBulletHitNotify)
+public class HandlerEvtBulletHitNotify extends PacketHandler {
+    @Override
+    public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
+        session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtBulletHitNotify(EvtBulletHitNotifyOuterClass.EvtBulletHitNotify.parseFrom(payload)));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtBulletMoveNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtBulletMoveNotify.java
new file mode 100644
index 000000000..fe7ddba57
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtBulletMoveNotify.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.EvtBulletMoveNotifyOuterClass;
+import emu.grasscutter.server.game.GameSession;
+import emu.grasscutter.server.packet.send.PacketEvtBulletMoveNotify;
+
+@Opcodes(PacketOpcodes.EvtBulletMoveNotify)
+public class HandlerEvtBulletMoveNotify extends PacketHandler {
+    @Override
+    public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
+        session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketEvtBulletMoveNotify(EvtBulletMoveNotifyOuterClass.EvtBulletMoveNotify.parseFrom(payload)));
+    }
+}
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/HandlerMassiveEntityElementOpBatchNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMassiveEntityElementOpBatchNotify.java
new file mode 100644
index 000000000..cc572cda2
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerMassiveEntityElementOpBatchNotify.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.MassiveEntityElementOpBatchNotifyOuterClass;
+import emu.grasscutter.server.game.GameSession;
+import emu.grasscutter.server.packet.send.PacketMassiveEntityElementOpBatchNotify;
+
+@Opcodes(PacketOpcodes.MassiveEntityElementOpBatchNotify)
+public class HandlerMassiveEntityElementOpBatchNotify extends PacketHandler {
+    @Override
+    public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
+        session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), new PacketMassiveEntityElementOpBatchNotify(MassiveEntityElementOpBatchNotifyOuterClass.MassiveEntityElementOpBatchNotify.parseFrom(payload)));
+    }
+}
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/HandlerPlayerLoginReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java
index ff9495636..f01a79d7a 100644
--- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java
+++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java
@@ -9,7 +9,6 @@ import emu.grasscutter.net.proto.PlayerLoginReqOuterClass.PlayerLoginReq;
 import emu.grasscutter.server.game.GameSession;
 import emu.grasscutter.server.game.GameSession.SessionState;
 import emu.grasscutter.server.packet.send.PacketPlayerLoginRsp;
-import emu.grasscutter.server.packet.send.PacketTakeAchievementRewardReq;
 
 @Opcodes(PacketOpcodes.PlayerLoginReq) // Sends initial data packets
 public class HandlerPlayerLoginReq extends PacketHandler {
@@ -46,6 +45,5 @@ public class HandlerPlayerLoginReq extends PacketHandler {
 
         // Final packet to tell client logging in is done
         session.send(new PacketPlayerLoginRsp(session));
-        session.send(new PacketTakeAchievementRewardReq(session));
     }
 }
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/PacketEvtAvatarEnterFocusNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtAvatarEnterFocusNotify.java
new file mode 100644
index 000000000..c348a9180
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtAvatarEnterFocusNotify.java
@@ -0,0 +1,13 @@
+package emu.grasscutter.server.packet.send;
+
+import emu.grasscutter.net.packet.BasePacket;
+import emu.grasscutter.net.packet.PacketOpcodes;
+import emu.grasscutter.net.proto.EvtAvatarEnterFocusNotifyOuterClass;
+
+public class PacketEvtAvatarEnterFocusNotify extends BasePacket {
+    public PacketEvtAvatarEnterFocusNotify(EvtAvatarEnterFocusNotifyOuterClass.EvtAvatarEnterFocusNotify notify) {
+        super(PacketOpcodes.EvtAvatarEnterFocusNotify);
+
+        this.setData(EvtAvatarEnterFocusNotifyOuterClass.EvtAvatarEnterFocusNotify.newBuilder(notify));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketEvtAvatarExitFocusNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtAvatarExitFocusNotify.java
new file mode 100644
index 000000000..7b63b083e
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtAvatarExitFocusNotify.java
@@ -0,0 +1,13 @@
+package emu.grasscutter.server.packet.send;
+
+import emu.grasscutter.net.packet.BasePacket;
+import emu.grasscutter.net.packet.PacketOpcodes;
+import emu.grasscutter.net.proto.EvtAvatarExitFocusNotifyOuterClass;
+
+public class PacketEvtAvatarExitFocusNotify extends BasePacket {
+    public PacketEvtAvatarExitFocusNotify(EvtAvatarExitFocusNotifyOuterClass.EvtAvatarExitFocusNotify notify) {
+        super(PacketOpcodes.EvtAvatarExitFocusNotify);
+
+        this.setData(EvtAvatarExitFocusNotifyOuterClass.EvtAvatarExitFocusNotify.newBuilder(notify));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketEvtAvatarUpdateFocusNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtAvatarUpdateFocusNotify.java
new file mode 100644
index 000000000..667ab3d39
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtAvatarUpdateFocusNotify.java
@@ -0,0 +1,13 @@
+package emu.grasscutter.server.packet.send;
+
+import emu.grasscutter.net.packet.BasePacket;
+import emu.grasscutter.net.packet.PacketOpcodes;
+import emu.grasscutter.net.proto.EvtAvatarUpdateFocusNotifyOuterClass;
+
+public class PacketEvtAvatarUpdateFocusNotify extends BasePacket {
+    public PacketEvtAvatarUpdateFocusNotify(EvtAvatarUpdateFocusNotifyOuterClass.EvtAvatarUpdateFocusNotify notify) {
+        super(PacketOpcodes.EvtAvatarUpdateFocusNotify);
+
+        this.setData(EvtAvatarUpdateFocusNotifyOuterClass.EvtAvatarUpdateFocusNotify.newBuilder(notify));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketEvtBulletDeactiveNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtBulletDeactiveNotify.java
new file mode 100644
index 000000000..3a61e108c
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtBulletDeactiveNotify.java
@@ -0,0 +1,13 @@
+package emu.grasscutter.server.packet.send;
+
+import emu.grasscutter.net.packet.BasePacket;
+import emu.grasscutter.net.packet.PacketOpcodes;
+import emu.grasscutter.net.proto.EvtBulletDeactiveNotifyOuterClass;
+
+public class PacketEvtBulletDeactiveNotify extends BasePacket {
+    public PacketEvtBulletDeactiveNotify(EvtBulletDeactiveNotifyOuterClass.EvtBulletDeactiveNotify notify) {
+        super(PacketOpcodes.EvtBulletDeactiveNotify);
+
+        this.setData(EvtBulletDeactiveNotifyOuterClass.EvtBulletDeactiveNotify.newBuilder(notify));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketEvtBulletHitNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtBulletHitNotify.java
new file mode 100644
index 000000000..e86ab6079
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtBulletHitNotify.java
@@ -0,0 +1,13 @@
+package emu.grasscutter.server.packet.send;
+
+import emu.grasscutter.net.packet.BasePacket;
+import emu.grasscutter.net.packet.PacketOpcodes;
+import emu.grasscutter.net.proto.EvtBulletHitNotifyOuterClass;
+
+public class PacketEvtBulletHitNotify extends BasePacket {
+    public PacketEvtBulletHitNotify(EvtBulletHitNotifyOuterClass.EvtBulletHitNotify notify) {
+        super(PacketOpcodes.EvtBulletHitNotify);
+
+        this.setData(EvtBulletHitNotifyOuterClass.EvtBulletHitNotify.newBuilder(notify));
+    }
+}
diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketEvtBulletMoveNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtBulletMoveNotify.java
new file mode 100644
index 000000000..361d7fafe
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketEvtBulletMoveNotify.java
@@ -0,0 +1,13 @@
+package emu.grasscutter.server.packet.send;
+
+import emu.grasscutter.net.packet.BasePacket;
+import emu.grasscutter.net.packet.PacketOpcodes;
+import emu.grasscutter.net.proto.EvtBulletMoveNotifyOuterClass;
+
+public class PacketEvtBulletMoveNotify extends BasePacket {
+    public PacketEvtBulletMoveNotify(EvtBulletMoveNotifyOuterClass.EvtBulletMoveNotify notify) {
+        super(PacketOpcodes.EvtBulletMoveNotify);
+
+        this.setData(EvtBulletMoveNotifyOuterClass.EvtBulletMoveNotify.newBuilder(notify));
+    }
+}
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..908dabd1b 100644
--- a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeMarkPointNotify.java
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeMarkPointNotify.java
@@ -1,11 +1,14 @@
 package emu.grasscutter.server.packet.send;
 
 import emu.grasscutter.game.home.HomeBlockItem;
+import emu.grasscutter.game.home.HomeMarkPointProtoFactory;
 import emu.grasscutter.game.player.Player;
 import emu.grasscutter.net.packet.BasePacket;
 import emu.grasscutter.net.packet.PacketOpcodes;
 import emu.grasscutter.net.proto.HomeMarkPointNotifyOuterClass;
 import emu.grasscutter.net.proto.HomeMarkPointSceneDataOuterClass;
+import emu.grasscutter.net.proto.VectorOuterClass;
+
 import java.util.Collection;
 
 public class PacketHomeMarkPointNotify extends BasePacket {
@@ -14,28 +17,30 @@ public class PacketHomeMarkPointNotify extends BasePacket {
         super(PacketOpcodes.HomeMarkPointNotify);
 
         var proto = HomeMarkPointNotifyOuterClass.HomeMarkPointNotify.newBuilder();
+        var world = player.getCurHomeWorld();
+        var owner = world.getHost();
+        var home = world.getHome();
 
-        if (player.getRealmList() == null) {
+        if (owner.getRealmList() == null) {
             return;
         }
-        for (var moduleId : player.getRealmList()) {
-            var homeScene = player.getHome().getHomeSceneItem(moduleId + 2000);
+
+        for (var moduleId : owner.getRealmList()) {
+            var homeScene = home.getHomeSceneItem(moduleId + 2000);
 
             var markPointData =
-                    HomeMarkPointSceneDataOuterClass.HomeMarkPointSceneData.newBuilder()
-                            .setModuleId(moduleId)
-                            .setSceneId(moduleId + 2000)
-                            .setTeapotSpiritPos(homeScene.getDjinnPos().toProto());
+                HomeMarkPointSceneDataOuterClass.HomeMarkPointSceneData.newBuilder()
+                    .setModuleId(moduleId)
+                    .setSceneId(moduleId + 2000)
+                    .setSafePointPos(homeScene.isRoom() ? VectorOuterClass.Vector.newBuilder().build() : world.getSceneById(moduleId + 2000).getScriptManager().getConfig().born_pos.toProto())
+                    .setTeapotSpiritPos(homeScene.isRoom() ? VectorOuterClass.Vector.newBuilder().build() : homeScene.getDjinnPos().toProto());
 
-            // Now it only supports the teleport point
-            // TODO add more types
-            var marks =
-                    homeScene.getBlockItems().values().stream()
-                            .map(HomeBlockItem::getDeployFurnitureList)
-                            .flatMap(Collection::stream)
-                            .filter(i -> i.getFurnitureId() == 373501)
-                            .map(x -> x.toMarkPointProto(3))
-                            .toList();
+            var marks = homeScene.getBlockItems().values().stream()
+                .map(HomeBlockItem::getMarkPointProtoFactories)
+                .flatMap(Collection::stream)
+                .filter(HomeMarkPointProtoFactory::isProtoConvertible)
+                .map(HomeMarkPointProtoFactory::toMarkPointProto)
+                .toList();
 
             markPointData.addAllFurnitureList(marks);
             proto.addMarkPointDataList(markPointData);
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/PacketMassiveEntityElementOpBatchNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketMassiveEntityElementOpBatchNotify.java
new file mode 100644
index 000000000..1e3c670a8
--- /dev/null
+++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMassiveEntityElementOpBatchNotify.java
@@ -0,0 +1,13 @@
+package emu.grasscutter.server.packet.send;
+
+import emu.grasscutter.net.packet.BasePacket;
+import emu.grasscutter.net.packet.PacketOpcodes;
+import emu.grasscutter.net.proto.MassiveEntityElementOpBatchNotifyOuterClass;
+
+public class PacketMassiveEntityElementOpBatchNotify extends BasePacket {
+    public PacketMassiveEntityElementOpBatchNotify(MassiveEntityElementOpBatchNotifyOuterClass.MassiveEntityElementOpBatchNotify notify) {
+        super(PacketOpcodes.MassiveEntityElementOpBatchNotify);
+
+        this.setData(MassiveEntityElementOpBatchNotifyOuterClass.MassiveEntityElementOpBatchNotify.newBuilder(notify));
+    }
+}
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();