diff --git a/src/generated/main/java/emu/grasscutter/net/proto/HomePlantSubFieldDataOuterClass.java b/src/generated/main/java/emu/grasscutter/net/proto/HomePlantSubFieldDataOuterClass.java
index e41b29c80..5e5a599f8 100644
--- a/src/generated/main/java/emu/grasscutter/net/proto/HomePlantSubFieldDataOuterClass.java
+++ b/src/generated/main/java/emu/grasscutter/net/proto/HomePlantSubFieldDataOuterClass.java
@@ -36,21 +36,21 @@ public final class HomePlantSubFieldDataOuterClass {
int getEntityIdList(int index);
/**
- * .HomePlantFieldStatus CAKDDMKAIMD = 7;
- * @return The enum numeric value on the wire for cAKDDMKAIMD.
+ * .HomePlantFieldStatus status = 7;
+ * @return The enum numeric value on the wire for status.
*/
- int getCAKDDMKAIMDValue();
+ int getStatusValue();
/**
- * .HomePlantFieldStatus CAKDDMKAIMD = 7;
- * @return The cAKDDMKAIMD.
+ * .HomePlantFieldStatus status = 7;
+ * @return The status.
*/
- emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getCAKDDMKAIMD();
+ emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getStatus();
/**
- * uint32 JHFNDBIHLNB = 8;
- * @return The jHFNDBIHLNB.
+ * uint32 seed_id = 8;
+ * @return The seedId.
*/
- int getJHFNDBIHLNB();
+ int getSeedId();
/**
* fixed32 end_time = 14;
@@ -59,10 +59,10 @@ public final class HomePlantSubFieldDataOuterClass {
int getEndTime();
/**
- * uint32 KHFGOPCOAGM = 3;
- * @return The kHFGOPCOAGM.
+ * uint32 gather_point_type = 3;
+ * @return The gatherPointType.
*/
- int getKHFGOPCOAGM();
+ int getGatherPointType();
}
/**
*
@@ -82,7 +82,7 @@ public final class HomePlantSubFieldDataOuterClass { } private HomePlantSubFieldData() { entityIdList_ = emptyIntList(); - cAKDDMKAIMD_ = 0; + status_ = 0; } @java.lang.Override @@ -118,7 +118,7 @@ public final class HomePlantSubFieldDataOuterClass { break; case 24: { - kHFGOPCOAGM_ = input.readUInt32(); + gatherPointType_ = input.readUInt32(); break; } case 48: { @@ -145,12 +145,12 @@ public final class HomePlantSubFieldDataOuterClass { case 56: { int rawValue = input.readEnum(); - cAKDDMKAIMD_ = rawValue; + status_ = rawValue; break; } case 64: { - jHFNDBIHLNB_ = input.readUInt32(); + seedId_ = input.readUInt32(); break; } case 117: { @@ -221,34 +221,34 @@ public final class HomePlantSubFieldDataOuterClass { } private int entityIdListMemoizedSerializedSize = -1; - public static final int CAKDDMKAIMD_FIELD_NUMBER = 7; - private int cAKDDMKAIMD_; + public static final int STATUS_FIELD_NUMBER = 7; + private int status_; /** - *.HomePlantFieldStatus CAKDDMKAIMD = 7;
- * @return The enum numeric value on the wire for cAKDDMKAIMD. + *.HomePlantFieldStatus status = 7;
+ * @return The enum numeric value on the wire for status. */ - @java.lang.Override public int getCAKDDMKAIMDValue() { - return cAKDDMKAIMD_; + @java.lang.Override public int getStatusValue() { + return status_; } /** - *.HomePlantFieldStatus CAKDDMKAIMD = 7;
- * @return The cAKDDMKAIMD. + *.HomePlantFieldStatus status = 7;
+ * @return The status. */ - @java.lang.Override public emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getCAKDDMKAIMD() { + @java.lang.Override public emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getStatus() { @SuppressWarnings("deprecation") - emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus result = emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.valueOf(cAKDDMKAIMD_); + emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus result = emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.valueOf(status_); return result == null ? emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.UNRECOGNIZED : result; } - public static final int JHFNDBIHLNB_FIELD_NUMBER = 8; - private int jHFNDBIHLNB_; + public static final int SEED_ID_FIELD_NUMBER = 8; + private int seedId_; /** - *uint32 JHFNDBIHLNB = 8;
- * @return The jHFNDBIHLNB. + *uint32 seed_id = 8;
+ * @return The seedId. */ @java.lang.Override - public int getJHFNDBIHLNB() { - return jHFNDBIHLNB_; + public int getSeedId() { + return seedId_; } public static final int END_TIME_FIELD_NUMBER = 14; @@ -262,15 +262,15 @@ public final class HomePlantSubFieldDataOuterClass { return endTime_; } - public static final int KHFGOPCOAGM_FIELD_NUMBER = 3; - private int kHFGOPCOAGM_; + public static final int GATHER_POINT_TYPE_FIELD_NUMBER = 3; + private int gatherPointType_; /** - *uint32 KHFGOPCOAGM = 3;
- * @return The kHFGOPCOAGM. + *uint32 gather_point_type = 3;
+ * @return The gatherPointType. */ @java.lang.Override - public int getKHFGOPCOAGM() { - return kHFGOPCOAGM_; + public int getGatherPointType() { + return gatherPointType_; } private byte memoizedIsInitialized = -1; @@ -288,8 +288,8 @@ public final class HomePlantSubFieldDataOuterClass { public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { getSerializedSize(); - if (kHFGOPCOAGM_ != 0) { - output.writeUInt32(3, kHFGOPCOAGM_); + if (gatherPointType_ != 0) { + output.writeUInt32(3, gatherPointType_); } if (getEntityIdListList().size() > 0) { output.writeUInt32NoTag(50); @@ -298,11 +298,11 @@ public final class HomePlantSubFieldDataOuterClass { for (int i = 0; i < entityIdList_.size(); i++) { output.writeUInt32NoTag(entityIdList_.getInt(i)); } - if (cAKDDMKAIMD_ != emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.HOME_FIELD_STATUE_NONE.getNumber()) { - output.writeEnum(7, cAKDDMKAIMD_); + if (status_ != emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.HOME_FIELD_STATUE_NONE.getNumber()) { + output.writeEnum(7, status_); } - if (jHFNDBIHLNB_ != 0) { - output.writeUInt32(8, jHFNDBIHLNB_); + if (seedId_ != 0) { + output.writeUInt32(8, seedId_); } if (endTime_ != 0) { output.writeFixed32(14, endTime_); @@ -316,9 +316,9 @@ public final class HomePlantSubFieldDataOuterClass { if (size != -1) return size; size = 0; - if (kHFGOPCOAGM_ != 0) { + if (gatherPointType_ != 0) { size += com.google.protobuf.CodedOutputStream - .computeUInt32Size(3, kHFGOPCOAGM_); + .computeUInt32Size(3, gatherPointType_); } { int dataSize = 0; @@ -334,13 +334,13 @@ public final class HomePlantSubFieldDataOuterClass { } entityIdListMemoizedSerializedSize = dataSize; } - if (cAKDDMKAIMD_ != emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.HOME_FIELD_STATUE_NONE.getNumber()) { + if (status_ != emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.HOME_FIELD_STATUE_NONE.getNumber()) { size += com.google.protobuf.CodedOutputStream - .computeEnumSize(7, cAKDDMKAIMD_); + .computeEnumSize(7, status_); } - if (jHFNDBIHLNB_ != 0) { + if (seedId_ != 0) { size += com.google.protobuf.CodedOutputStream - .computeUInt32Size(8, jHFNDBIHLNB_); + .computeUInt32Size(8, seedId_); } if (endTime_ != 0) { size += com.google.protobuf.CodedOutputStream @@ -363,13 +363,13 @@ public final class HomePlantSubFieldDataOuterClass { if (!getEntityIdListList() .equals(other.getEntityIdListList())) return false; - if (cAKDDMKAIMD_ != other.cAKDDMKAIMD_) return false; - if (getJHFNDBIHLNB() - != other.getJHFNDBIHLNB()) return false; + if (status_ != other.status_) return false; + if (getSeedId() + != other.getSeedId()) return false; if (getEndTime() != other.getEndTime()) return false; - if (getKHFGOPCOAGM() - != other.getKHFGOPCOAGM()) return false; + if (getGatherPointType() + != other.getGatherPointType()) return false; if (!unknownFields.equals(other.unknownFields)) return false; return true; } @@ -385,14 +385,14 @@ public final class HomePlantSubFieldDataOuterClass { hash = (37 * hash) + ENTITY_ID_LIST_FIELD_NUMBER; hash = (53 * hash) + getEntityIdListList().hashCode(); } - hash = (37 * hash) + CAKDDMKAIMD_FIELD_NUMBER; - hash = (53 * hash) + cAKDDMKAIMD_; - hash = (37 * hash) + JHFNDBIHLNB_FIELD_NUMBER; - hash = (53 * hash) + getJHFNDBIHLNB(); + hash = (37 * hash) + STATUS_FIELD_NUMBER; + hash = (53 * hash) + status_; + hash = (37 * hash) + SEED_ID_FIELD_NUMBER; + hash = (53 * hash) + getSeedId(); hash = (37 * hash) + END_TIME_FIELD_NUMBER; hash = (53 * hash) + getEndTime(); - hash = (37 * hash) + KHFGOPCOAGM_FIELD_NUMBER; - hash = (53 * hash) + getKHFGOPCOAGM(); + hash = (37 * hash) + GATHER_POINT_TYPE_FIELD_NUMBER; + hash = (53 * hash) + getGatherPointType(); hash = (29 * hash) + unknownFields.hashCode(); memoizedHashCode = hash; return hash; @@ -532,13 +532,13 @@ public final class HomePlantSubFieldDataOuterClass { super.clear(); entityIdList_ = emptyIntList(); bitField0_ = (bitField0_ & ~0x00000001); - cAKDDMKAIMD_ = 0; + status_ = 0; - jHFNDBIHLNB_ = 0; + seedId_ = 0; endTime_ = 0; - kHFGOPCOAGM_ = 0; + gatherPointType_ = 0; return this; } @@ -572,10 +572,10 @@ public final class HomePlantSubFieldDataOuterClass { bitField0_ = (bitField0_ & ~0x00000001); } result.entityIdList_ = entityIdList_; - result.cAKDDMKAIMD_ = cAKDDMKAIMD_; - result.jHFNDBIHLNB_ = jHFNDBIHLNB_; + result.status_ = status_; + result.seedId_ = seedId_; result.endTime_ = endTime_; - result.kHFGOPCOAGM_ = kHFGOPCOAGM_; + result.gatherPointType_ = gatherPointType_; onBuilt(); return result; } @@ -634,17 +634,17 @@ public final class HomePlantSubFieldDataOuterClass { } onChanged(); } - if (other.cAKDDMKAIMD_ != 0) { - setCAKDDMKAIMDValue(other.getCAKDDMKAIMDValue()); + if (other.status_ != 0) { + setStatusValue(other.getStatusValue()); } - if (other.getJHFNDBIHLNB() != 0) { - setJHFNDBIHLNB(other.getJHFNDBIHLNB()); + if (other.getSeedId() != 0) { + setSeedId(other.getSeedId()); } if (other.getEndTime() != 0) { setEndTime(other.getEndTime()); } - if (other.getKHFGOPCOAGM() != 0) { - setKHFGOPCOAGM(other.getKHFGOPCOAGM()); + if (other.getGatherPointType() != 0) { + setGatherPointType(other.getGatherPointType()); } this.mergeUnknownFields(other.unknownFields); onChanged(); @@ -755,87 +755,87 @@ public final class HomePlantSubFieldDataOuterClass { return this; } - private int cAKDDMKAIMD_ = 0; + private int status_ = 0; /** - *.HomePlantFieldStatus CAKDDMKAIMD = 7;
- * @return The enum numeric value on the wire for cAKDDMKAIMD. + *.HomePlantFieldStatus status = 7;
+ * @return The enum numeric value on the wire for status. */ - @java.lang.Override public int getCAKDDMKAIMDValue() { - return cAKDDMKAIMD_; + @java.lang.Override public int getStatusValue() { + return status_; } /** - *.HomePlantFieldStatus CAKDDMKAIMD = 7;
- * @param value The enum numeric value on the wire for cAKDDMKAIMD to set. + *.HomePlantFieldStatus status = 7;
+ * @param value The enum numeric value on the wire for status to set. * @return This builder for chaining. */ - public Builder setCAKDDMKAIMDValue(int value) { + public Builder setStatusValue(int value) { - cAKDDMKAIMD_ = value; + status_ = value; onChanged(); return this; } /** - *.HomePlantFieldStatus CAKDDMKAIMD = 7;
- * @return The cAKDDMKAIMD. + *.HomePlantFieldStatus status = 7;
+ * @return The status. */ @java.lang.Override - public emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getCAKDDMKAIMD() { + public emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus getStatus() { @SuppressWarnings("deprecation") - emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus result = emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.valueOf(cAKDDMKAIMD_); + emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus result = emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.valueOf(status_); return result == null ? emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus.UNRECOGNIZED : result; } /** - *.HomePlantFieldStatus CAKDDMKAIMD = 7;
- * @param value The cAKDDMKAIMD to set. + *.HomePlantFieldStatus status = 7;
+ * @param value The status to set. * @return This builder for chaining. */ - public Builder setCAKDDMKAIMD(emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus value) { + public Builder setStatus(emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.HomePlantFieldStatus value) { if (value == null) { throw new NullPointerException(); } - cAKDDMKAIMD_ = value.getNumber(); + status_ = value.getNumber(); onChanged(); return this; } /** - *.HomePlantFieldStatus CAKDDMKAIMD = 7;
+ *.HomePlantFieldStatus status = 7;
* @return This builder for chaining. */ - public Builder clearCAKDDMKAIMD() { + public Builder clearStatus() { - cAKDDMKAIMD_ = 0; + status_ = 0; onChanged(); return this; } - private int jHFNDBIHLNB_ ; + private int seedId_ ; /** - *uint32 JHFNDBIHLNB = 8;
- * @return The jHFNDBIHLNB. + *uint32 seed_id = 8;
+ * @return The seedId. */ @java.lang.Override - public int getJHFNDBIHLNB() { - return jHFNDBIHLNB_; + public int getSeedId() { + return seedId_; } /** - *uint32 JHFNDBIHLNB = 8;
- * @param value The jHFNDBIHLNB to set. + *uint32 seed_id = 8;
+ * @param value The seedId to set. * @return This builder for chaining. */ - public Builder setJHFNDBIHLNB(int value) { + public Builder setSeedId(int value) { - jHFNDBIHLNB_ = value; + seedId_ = value; onChanged(); return this; } /** - *uint32 JHFNDBIHLNB = 8;
+ *uint32 seed_id = 8;
* @return This builder for chaining. */ - public Builder clearJHFNDBIHLNB() { + public Builder clearSeedId() { - jHFNDBIHLNB_ = 0; + seedId_ = 0; onChanged(); return this; } @@ -871,33 +871,33 @@ public final class HomePlantSubFieldDataOuterClass { return this; } - private int kHFGOPCOAGM_ ; + private int gatherPointType_ ; /** - *uint32 KHFGOPCOAGM = 3;
- * @return The kHFGOPCOAGM. + *uint32 gather_point_type = 3;
+ * @return The gatherPointType. */ @java.lang.Override - public int getKHFGOPCOAGM() { - return kHFGOPCOAGM_; + public int getGatherPointType() { + return gatherPointType_; } /** - *uint32 KHFGOPCOAGM = 3;
- * @param value The kHFGOPCOAGM to set. + *uint32 gather_point_type = 3;
+ * @param value The gatherPointType to set. * @return This builder for chaining. */ - public Builder setKHFGOPCOAGM(int value) { + public Builder setGatherPointType(int value) { - kHFGOPCOAGM_ = value; + gatherPointType_ = value; onChanged(); return this; } /** - *uint32 KHFGOPCOAGM = 3;
+ *uint32 gather_point_type = 3;
* @return This builder for chaining. */ - public Builder clearKHFGOPCOAGM() { + public Builder clearGatherPointType() { - kHFGOPCOAGM_ = 0; + gatherPointType_ = 0; onChanged(); return this; } @@ -969,12 +969,12 @@ public final class HomePlantSubFieldDataOuterClass { static { java.lang.String[] descriptorData = { "\n\033HomePlantSubFieldData.proto\032\032HomePlant" + - "FieldStatus.proto\"\227\001\n\025HomePlantSubFieldD" + - "ata\022\026\n\016entity_id_list\030\006 \003(\r\022*\n\013CAKDDMKAI" + - "MD\030\007 \001(\0162\025.HomePlantFieldStatus\022\023\n\013JHFND" + - "BIHLNB\030\010 \001(\r\022\020\n\010end_time\030\016 \001(\007\022\023\n\013KHFGOP" + - "COAGM\030\003 \001(\rB\033\n\031emu.grasscutter.net.proto" + - "b\006proto3" + "FieldStatus.proto\"\224\001\n\025HomePlantSubFieldD" + + "ata\022\026\n\016entity_id_list\030\006 \003(\r\022%\n\006status\030\007 " + + "\001(\0162\025.HomePlantFieldStatus\022\017\n\007seed_id\030\010 " + + "\001(\r\022\020\n\010end_time\030\016 \001(\007\022\031\n\021gather_point_ty" + + "pe\030\003 \001(\rB\033\n\031emu.grasscutter.net.protob\006p" + + "roto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, @@ -986,7 +986,7 @@ public final class HomePlantSubFieldDataOuterClass { internal_static_HomePlantSubFieldData_fieldAccessorTable = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_HomePlantSubFieldData_descriptor, - new java.lang.String[] { "EntityIdList", "CAKDDMKAIMD", "JHFNDBIHLNB", "EndTime", "KHFGOPCOAGM", }); + new java.lang.String[] { "EntityIdList", "Status", "SeedId", "EndTime", "GatherPointType", }); emu.grasscutter.net.proto.HomePlantFieldStatusOuterClass.getDescriptor(); } diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index 400cade1e..24b9cbb7e 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -286,6 +286,10 @@ public final class GameData { private static final Int2ObjectMaphomeWorldBgmDataMap = new Int2ObjectOpenHashMap<>(); + @Getter + private static final Int2ObjectMap homeWorldEventDataMap = + new Int2ObjectOpenHashMap<>(); + @Getter private static final Int2ObjectMap homeWorldLevelDataMap = new Int2ObjectOpenHashMap<>(); diff --git a/src/main/java/emu/grasscutter/data/excels/HomeWorldEventData.java b/src/main/java/emu/grasscutter/data/excels/HomeWorldEventData.java new file mode 100644 index 000000000..d5977c817 --- /dev/null +++ b/src/main/java/emu/grasscutter/data/excels/HomeWorldEventData.java @@ -0,0 +1,25 @@ +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.home.suite.event.SuiteEventType; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +@ResourceType(name = "HomeWorldEventExcelConfigData.json") +@FieldDefaults(level = AccessLevel.PRIVATE) +@Getter +public class HomeWorldEventData extends GameResource { + @SerializedName(value = "id", alternate = {"BBEIIPEFDPE"}) + int id; + @SerializedName(value = "eventType", alternate = {"JOCKIMECHDP"}) + SuiteEventType eventType; + int avatarID; + @SerializedName(value = "talkId", alternate = {"IGNJAICDFPD"}) + int talkId; + int rewardID; + @SerializedName(value = "suiteId", alternate = {"FEHOKMJPOED"}) + int suiteId; +} diff --git a/src/main/java/emu/grasscutter/game/entity/EntityHomeAnimal.java b/src/main/java/emu/grasscutter/game/entity/EntityHomeAnimal.java index 426849aa9..c6652d967 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityHomeAnimal.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityHomeAnimal.java @@ -10,12 +10,14 @@ import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify; import emu.grasscutter.server.packet.send.PacketSceneEntityDisappearNotify; import lombok.Getter; +import java.util.concurrent.atomic.AtomicBoolean; + public class EntityHomeAnimal extends EntityMonster implements Rebornable { private int rebornCDTickCount; private final Position rebornPos; @Getter private final int rebirth; @Getter private final int rebirthCD; - private boolean disappeared; + private final AtomicBoolean disappeared = new AtomicBoolean(); public EntityHomeAnimal(Scene scene, HomeWorldAnimalData data, Position pos) { super(scene, GameData.getMonsterDataMap().get(data.getMonsterID()), pos, 1); @@ -60,13 +62,13 @@ public class EntityHomeAnimal extends EntityMonster implements Rebornable { new PacketSceneEntityDisappearNotify( this, VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE)); this.rebornCDTickCount = this.getRebornCD(); - this.disappeared = true; + this.disappeared.set(true); } @Override public void reborn() { - if (this.disappeared) { - this.disappeared = false; + if (this.disappeared.get()) { + this.disappeared.set(false); this.getPosition().set(this.getRebornPos()); this.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(this)); } @@ -74,6 +76,6 @@ public class EntityHomeAnimal extends EntityMonster implements Rebornable { @Override public boolean isInCD() { - return this.disappeared; + return this.disappeared.get(); } } diff --git a/src/main/java/emu/grasscutter/game/home/GameHome.java b/src/main/java/emu/grasscutter/game/home/GameHome.java index 52f58e3f6..fd5bcc893 100644 --- a/src/main/java/emu/grasscutter/game/home/GameHome.java +++ b/src/main/java/emu/grasscutter/game/home/GameHome.java @@ -12,15 +12,17 @@ import emu.grasscutter.game.props.SceneType; import emu.grasscutter.net.proto.HomeAvatarTalkFinishInfoOuterClass; 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; +import java.util.stream.Stream; @Entity(value = "homes", useDiscriminator = false) @Data @@ -55,6 +57,7 @@ public class GameHome { Set unlockedHomeBgmList; int enterHomeOption; Map > finishedTalkIdMap; + Set finishedRewardEventIdSet; public static GameHome getByUid(Integer uid) { var home = DatabaseHelper.getHomeByUid(uid); @@ -62,7 +65,9 @@ public class GameHome { home = GameHome.create(uid); } + home.reassignIfNull(); home.fixMainHouseIfOld(); + home.syncHomeAvatarCostume(); return home; } @@ -79,9 +84,19 @@ public class GameHome { .mainHouseMap(new ConcurrentHashMap<>()) .unlockedHomeBgmList(new HashSet<>()) .finishedTalkIdMap(new HashMap<>()) + .finishedRewardEventIdSet(new HashSet<>()) .build(); } + // avoid NPE caused by database remover. + private void reassignIfNull() { + this.getSceneMap().values().stream() + .map(HomeSceneItem::getBlockItems) + .map(Map::values) + .flatMap(Collection::stream) + .forEach(HomeBlockItem::reassignIfNull); + } + // Data fixer. private void fixMainHouseIfOld() { if (this.getMainHouseMap() == null) { @@ -97,6 +112,18 @@ public class GameHome { this.save(); } + private void syncHomeAvatarCostume() { + Stream.of(this.sceneMap, this.mainHouseMap) + .map(ConcurrentHashMap::values) + .flatMap(Collection::stream) + .map(HomeSceneItem::getBlockItems) + .map(Map::values) + .flatMap(Collection::stream) + .map(HomeBlockItem::getDeployNPCList) + .flatMap(Collection::stream) + .forEach(npc -> npc.setCostumeId(this.getPlayer().getCostumeFrom(npc.getAvatarId()))); + } + public void save() { DatabaseHelper.saveHome(this); } @@ -113,12 +140,12 @@ public class GameHome { 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); } + + return HomeSceneItem.parseFrom(defaultItem, sceneId); }); } @@ -149,6 +176,8 @@ public class GameHome { this.getMainHouseMap().remove(outdoor); // delete main house in current scene. this.getMainHouseItem(outdoor); // put new main house with default arrangement. this.save(); + + this.getPlayer().getCurHomeWorld().getModuleManager().refreshMainHouse(); } public void onOwnerLogin(Player player) { @@ -160,6 +189,8 @@ public class GameHome { player.getSession().send(new PacketHomeMarkPointNotify(player)); player.getSession().send(new PacketHomeAvatarTalkFinishInfoNotify(player)); player.getSession().send(new PacketHomeAllUnlockedBgmIdListNotify(player)); + player.getSession().send(new PacketHomeAvatarRewardEventNotify(player)); + player.getSession().send(new PacketHomeAvatarAllFinishRewardNotify(player)); checkAccumulatedResources(player); player.getSession().send(new PacketHomeResourceNotify(player)); } @@ -226,6 +257,20 @@ public class GameHome { .toList(); } + public boolean onClaimAvatarRewards(int eventId) { + if (this.finishedRewardEventIdSet == null) { + this.finishedRewardEventIdSet = new HashSet<>(); + } + + var success = this.finishedRewardEventIdSet.add(eventId); + this.save(); + return success; + } + + public boolean isRewardEventFinished(int eventId) { + return this.finishedRewardEventIdSet != null && this.finishedRewardEventIdSet.contains(eventId); + } + public boolean addUnlockedHomeBgm(int homeBgmId) { if (!getUnlockedHomeBgmList().add(homeBgmId)) return false; @@ -404,7 +449,7 @@ public class GameHome { newCoin = storedCoin + owedCoin; } // Ensure max is not exceeded - storedCoin = (maxCoin >= newCoin) ? newCoin : maxCoin; + storedCoin = Math.min(maxCoin, newCoin); } // Update fetter exp @@ -416,7 +461,7 @@ public class GameHome { newFetter = storedFetterExp + owedFetter; } // Ensure max is not exceeded - storedFetterExp = (maxFetter >= newFetter) ? newFetter : maxFetter; + storedFetterExp = Math.min(maxFetter, newFetter); } save(); diff --git a/src/main/java/emu/grasscutter/game/home/HomeBlockItem.java b/src/main/java/emu/grasscutter/game/home/HomeBlockItem.java index dbd080d46..3fa916e78 100644 --- a/src/main/java/emu/grasscutter/game/home/HomeBlockItem.java +++ b/src/main/java/emu/grasscutter/game/home/HomeBlockItem.java @@ -2,6 +2,8 @@ package emu.grasscutter.game.home; import dev.morphia.annotations.*; import emu.grasscutter.data.binout.HomeworldDefaultSaveData; +import emu.grasscutter.game.home.suite.HomeSuiteItem; +import emu.grasscutter.game.player.Player; import emu.grasscutter.net.proto.HomeBlockArrangementInfoOuterClass.HomeBlockArrangementInfo; import java.util.*; import java.util.stream.Stream; @@ -19,6 +21,7 @@ public class HomeBlockItem { List persistentFurnitureList; List deployAnimalList; List deployNPCList; + List suiteList; public static HomeBlockItem parseFrom(HomeworldDefaultSaveData.HomeBlock homeBlock) { // create from default setting @@ -37,10 +40,11 @@ public class HomeBlockItem { .toList()) .deployAnimalList(List.of()) .deployNPCList(List.of()) + .suiteList(List.of()) .build(); } - public void update(HomeBlockArrangementInfo homeBlockArrangementInfo) { + public void update(HomeBlockArrangementInfo homeBlockArrangementInfo, Player owner) { this.blockId = homeBlockArrangementInfo.getBlockId(); this.deployFurnitureList = @@ -60,8 +64,12 @@ public class HomeBlockItem { this.deployNPCList = homeBlockArrangementInfo.getDeployNpcListList().stream() - .map(HomeNPCItem::parseFrom) + .map(homeNpcData -> HomeNPCItem.parseFrom(homeNpcData, owner)) .toList(); + + this.suiteList = homeBlockArrangementInfo.getFurnitureSuiteListList().stream() + .map(HomeSuiteItem::parseFrom) + .toList(); } public int calComfort() { @@ -81,15 +89,16 @@ public class HomeBlockItem { this.persistentFurnitureList.forEach(f -> proto.addPersistentFurnitureList(f.toProto())); this.deployAnimalList.forEach(f -> proto.addDeployAnimalList(f.toProto())); this.deployNPCList.forEach(f -> proto.addDeployNpcList(f.toProto())); + this.suiteList.forEach(f -> proto.addFurnitureSuiteList(f.toProto())); return proto.build(); } - // TODO add more types (farm field and suite) + // TODO implement farm field. public List extends HomeMarkPointProtoFactory> getMarkPointProtoFactories() { this.reassignIfNull(); - return Stream.of(this.deployFurnitureList, this.persistentFurnitureList, this.deployNPCList) + return Stream.of(this.deployFurnitureList, this.persistentFurnitureList, this.deployNPCList, this.suiteList) .flatMap(Collection::stream) .toList(); } @@ -107,5 +116,8 @@ public class HomeBlockItem { if (this.deployNPCList == null) { this.deployNPCList = List.of(); } + if (this.suiteList == null) { + this.suiteList = List.of(); + } } } diff --git a/src/main/java/emu/grasscutter/game/home/HomeModuleManager.java b/src/main/java/emu/grasscutter/game/home/HomeModuleManager.java new file mode 100644 index 000000000..d49f5650f --- /dev/null +++ b/src/main/java/emu/grasscutter/game/home/HomeModuleManager.java @@ -0,0 +1,204 @@ +package emu.grasscutter.game.home; + +import com.github.davidmoten.guavamini.Lists; +import emu.grasscutter.Grasscutter; +import emu.grasscutter.game.home.suite.event.HomeAvatarRewardEvent; +import emu.grasscutter.game.home.suite.event.HomeAvatarSummonEvent; +import emu.grasscutter.game.home.suite.event.SuiteEventType; +import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.proto.HomeAvatarRewardEventNotifyOuterClass; +import emu.grasscutter.net.proto.HomeAvatarSummonAllEventNotifyOuterClass; +import emu.grasscutter.net.proto.RetcodeOuterClass; +import emu.grasscutter.server.packet.send.PacketHomeAvatarSummonAllEventNotify; +import emu.grasscutter.utils.Either; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +import java.util.*; +import java.util.stream.Stream; + +@Getter +@FieldDefaults(level = AccessLevel.PRIVATE) +public class HomeModuleManager { + final Player homeOwner; + final HomeWorld homeWorld; + final GameHome home; + final int moduleId; + final HomeScene outdoor; + HomeScene indoor; + final List rewardEvents; + final List summonEvents; + + public HomeModuleManager(HomeWorld homeWorld) { + this.homeOwner = homeWorld.getHost(); + this.homeWorld = homeWorld; + this.home = homeWorld.getHome(); + this.moduleId = this.homeOwner.getCurrentRealmId(); + this.outdoor = homeWorld.getSceneById(homeWorld.getActiveOutdoorSceneId()); + this.refreshMainHouse(); + this.rewardEvents = Lists.newArrayList(); + this.summonEvents = Collections.synchronizedList(Lists.newArrayList()); + } + + public void tick() { + this.outdoor.onTick(); + this.indoor.onTick(); + this.summonEvents.removeIf(HomeAvatarSummonEvent::isTimeOver); + } + + public void refreshMainHouse() { + this.indoor = this.homeWorld.getSceneById(this.homeWorld.getActiveIndoorSceneId()); + } + + public void onUpdateArrangement() { + this.fireAllAvatarRewardEvent(); + this.cancelSummonEventIfAvatarLeave(); + } + + private void fireAllAvatarRewardEvent() { + this.rewardEvents.clear(); + var allBlockItems = Stream.of(this.getOutdoorSceneItem(), this.getIndoorSceneItem()) + .map(HomeSceneItem::getBlockItems) + .map(Map::values) + .flatMap(Collection::stream) + .toList(); + + var suites = allBlockItems.stream() + .map(HomeBlockItem::getSuiteList) + .flatMap(Collection::stream) + .distinct() + .toList(); + + allBlockItems.stream() + .map(HomeBlockItem::getDeployNPCList) + .flatMap(Collection::stream) + .forEach(avatar -> { + suites.forEach(suite -> { + var data = SuiteEventType.HOME_AVATAR_REWARD_EVENT.getEventDataFrom(avatar.getAvatarId(), suite.getSuiteId()); + if (data == null || this.home.isRewardEventFinished(data.getId())) { + return; + } + + this.rewardEvents.add(new HomeAvatarRewardEvent(homeOwner, data.getId(), data.getRewardID(), data.getAvatarID(), data.getSuiteId(), suite.getGuid())); + }); + }); + + if (this.summonEvents != null) { + var suiteIdList = this.rewardEvents.stream().map(HomeAvatarRewardEvent::getSuiteId).toList(); + this.summonEvents.removeIf(event -> suiteIdList.contains(event.getSuiteId())); + } + } + + private void cancelSummonEventIfAvatarLeave() { + var avatars = Stream.of(this.getOutdoorSceneItem(), this.getIndoorSceneItem()) + .map(HomeSceneItem::getBlockItems) + .map(Map::values) + .flatMap(Collection::stream) + .map(HomeBlockItem::getDeployNPCList) + .flatMap(Collection::stream) + .map(HomeNPCItem::getAvatarId) + .toList(); + + this.summonEvents.removeIf(event -> !avatars.contains(event.getAvatarId())); + } + + public Either , Integer> claimAvatarRewards(int eventId) { + if (this.rewardEvents.isEmpty()) { + return Either.right(RetcodeOuterClass.Retcode.RET_FAIL_VALUE); + } + + var event = this.rewardEvents.remove(0); + if (event.getEventId() != eventId) { + return Either.right(RetcodeOuterClass.Retcode.RET_FAIL_VALUE); + } + + if (!this.homeOwner.getHome().onClaimAvatarRewards(eventId)) { + return Either.right(RetcodeOuterClass.Retcode.RET_FAIL_VALUE); + } + + return Either.left(event.giveRewards()); + } + + public Either
fireAvatarSummonEvent(Player owner, int avatarId, int guid, int suiteId) { + var targetSuite = ((HomeScene) owner.getScene()).getSceneItem().getBlockItems().values().stream() + .map(HomeBlockItem::getSuiteList) + .flatMap(Collection::stream) + .filter(suite -> suite.getGuid() == guid) + .findFirst() + .orElse(null); + + if (this.isInRewardEvent(avatarId)) { + return Either.right(RetcodeOuterClass.Retcode.RET_DUPLICATE_AVATAR_VALUE); + } + + if (this.rewardEvents.stream().anyMatch(event -> event.getGuid() == guid)) { + return Either.right(RetcodeOuterClass.Retcode.RET_HOME_FURNITURE_GUID_ERROR_VALUE); + } + + this.summonEvents.removeIf(event -> event.getGuid() == guid || event.getAvatarId() == avatarId); + + if (targetSuite == null) { + return Either.right(RetcodeOuterClass.Retcode.RET_HOME_CLIENT_PARAM_INVALID_VALUE); + } + + var eventData = SuiteEventType.HOME_AVATAR_SUMMON_EVENT.getEventDataFrom(avatarId, suiteId); + if (eventData == null) { + return Either.right(RetcodeOuterClass.Retcode.RET_HOME_CLIENT_PARAM_INVALID_VALUE); + } + + var event = new HomeAvatarSummonEvent(owner, eventData.getId(), eventData.getRewardID(), avatarId, suiteId, guid); + this.summonEvents.add(event); + owner.sendPacket(new PacketHomeAvatarSummonAllEventNotify(owner)); + return Either.left(event); + } + + public void onFinishSummonEvent(int eventId) { + this.summonEvents.removeIf(event -> event.getEventId() == eventId); + } + + public HomeAvatarRewardEventNotifyOuterClass.HomeAvatarRewardEventNotify toRewardEventProto() { + var notify = HomeAvatarRewardEventNotifyOuterClass.HomeAvatarRewardEventNotify.newBuilder(); + if (!this.rewardEvents.isEmpty()) { + notify.setRewardEvent(this.rewardEvents.get(0).toProto()).setIsEventTrigger(true); + + notify.addAllPendingList(this.rewardEvents.subList(1, this.rewardEvents.size()).stream() + .map(HomeAvatarRewardEvent::toProto) + .toList()); + } + + return notify.build(); + } + + public HomeAvatarSummonAllEventNotifyOuterClass.HomeAvatarSummonAllEventNotify toSummonEventProto() { + return HomeAvatarSummonAllEventNotifyOuterClass.HomeAvatarSummonAllEventNotify.newBuilder() + .addAllSummonEventList(this.summonEvents.stream() + .map(HomeAvatarSummonEvent::toProto) + .toList()) + .build(); + } + + public boolean isInRewardEvent(int avatarId) { + return this.rewardEvents.stream().anyMatch(e -> e.getAvatarId() == avatarId); + } + + public HomeSceneItem getOutdoorSceneItem() { + return this.outdoor.getSceneItem(); + } + + public HomeSceneItem getIndoorSceneItem() { + return this.indoor.getSceneItem(); + } + + public void onSetModule() { + this.outdoor.addEntities(this.getOutdoorSceneItem().getAnimals(this.outdoor)); + this.indoor.addEntities(this.getIndoorSceneItem().getAnimals(this.indoor)); + this.fireAllAvatarRewardEvent(); + } + + public void onRemovedModule() { + this.outdoor.getEntities().clear(); + this.indoor.getEntities().clear(); + } +} diff --git a/src/main/java/emu/grasscutter/game/home/HomeNPCItem.java b/src/main/java/emu/grasscutter/game/home/HomeNPCItem.java index fbd2ad377..7999fcd39 100644 --- a/src/main/java/emu/grasscutter/game/home/HomeNPCItem.java +++ b/src/main/java/emu/grasscutter/game/home/HomeNPCItem.java @@ -2,6 +2,7 @@ package emu.grasscutter.game.home; import dev.morphia.annotations.Entity; import emu.grasscutter.data.GameData; +import emu.grasscutter.game.player.Player; import emu.grasscutter.game.world.Position; import emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass; import emu.grasscutter.net.proto.HomeMarkPointNPCDataOuterClass; @@ -23,11 +24,12 @@ public class HomeNPCItem implements HomeMarkPointProtoFactory { Position spawnRot; int costumeId; - public static HomeNPCItem parseFrom(HomeNpcDataOuterClass.HomeNpcData homeNpcData) { + public static HomeNPCItem parseFrom(HomeNpcDataOuterClass.HomeNpcData homeNpcData, Player owner) { return HomeNPCItem.of() .avatarId(homeNpcData.getAvatarId()) .spawnPos(new Position(homeNpcData.getSpawnPos())) .spawnRot(new Position(homeNpcData.getSpawnRot())) + .costumeId(owner.getCostumeFrom(homeNpcData.getAvatarId())) .build(); } diff --git a/src/main/java/emu/grasscutter/game/home/HomeScene.java b/src/main/java/emu/grasscutter/game/home/HomeScene.java index b07f798b0..3c6df4b22 100644 --- a/src/main/java/emu/grasscutter/game/home/HomeScene.java +++ b/src/main/java/emu/grasscutter/game/home/HomeScene.java @@ -1,9 +1,12 @@ package emu.grasscutter.game.home; import emu.grasscutter.data.excels.scene.SceneData; +import emu.grasscutter.game.entity.EntityHomeAnimal; import emu.grasscutter.game.entity.GameEntity; +import emu.grasscutter.game.entity.Rebornable; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.world.Scene; +import emu.grasscutter.net.proto.VisionTypeOuterClass; import emu.grasscutter.server.packet.send.PacketSceneTimeNotify; public class HomeScene extends Scene { @@ -40,10 +43,31 @@ public class HomeScene extends Scene { .forEach(gameEntity -> gameEntity.onTick(this.getSceneTimeSeconds())); this.finishLoading(); - this.checkPlayerRespawn(); if (this.tickCount++ % 10 == 0) this.broadcastPacket(new PacketSceneTimeNotify(this)); } + public void onEnterEditModeFinish() { + this.removeEntities( + this.getEntities().values().stream() + .filter(gameEntity -> gameEntity instanceof EntityHomeAnimal) + .toList(), + VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE); + } + + public void onLeaveEditMode() { + this.addEntities(this.getSceneItem().getAnimals(this)); + } + + @Override + public void killEntity(GameEntity target, int attackerId) { + if (target instanceof Rebornable rebornable) { + rebornable.onAiKillSelf(); // Teapot animals will not die. They will revive! + return; + } + + super.killEntity(target, attackerId); + } + @Override public void checkNpcGroup() {} diff --git a/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java b/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java index 7449f029f..21da833dd 100644 --- a/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java +++ b/src/main/java/emu/grasscutter/game/home/HomeSceneItem.java @@ -6,17 +6,20 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.HomeworldDefaultSaveData; import emu.grasscutter.game.entity.EntityHomeAnimal; +import emu.grasscutter.game.player.Player; import emu.grasscutter.game.world.Position; import emu.grasscutter.game.world.Scene; import emu.grasscutter.net.proto.HomeSceneArrangementInfoOuterClass.HomeSceneArrangementInfo; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import javax.annotation.Nullable; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import javax.annotation.Nullable; -import lombok.*; -import lombok.experimental.FieldDefaults; @Entity @Data @@ -49,14 +52,14 @@ public class HomeSceneItem { .build(); } - public void update(HomeSceneArrangementInfo arrangementInfo) { + public void update(HomeSceneArrangementInfo arrangementInfo, Player owner) { for (var blockItem : arrangementInfo.getBlockArrangementInfoListList()) { var block = this.blockItems.get(blockItem.getBlockId()); if (block == null) { Grasscutter.getLogger().warn("Could not found the Home Block {}", blockItem.getBlockId()); continue; } - block.update(blockItem); + block.update(blockItem, owner); this.blockItems.put(blockItem.getBlockId(), block); } @@ -84,17 +87,13 @@ public class HomeSceneItem { } @Nullable public Position getTeleportPointPos(int guid) { - var pos = new AtomicReference (); - - this.getBlockItems().values().stream() + return this.getBlockItems().values().stream() .map(HomeBlockItem::getDeployFurnitureList) .flatMap(Collection::stream) .filter(homeFurnitureItem -> homeFurnitureItem.getGuid() == guid) .map(HomeFurnitureItem::getSpawnPos) .findFirst() - .ifPresent(pos::set); - - return pos.get(); + .orElse(null); } public List getAnimals(Scene scene) { diff --git a/src/main/java/emu/grasscutter/game/home/HomeWorld.java b/src/main/java/emu/grasscutter/game/home/HomeWorld.java index f2ea9d3b6..8f871657b 100644 --- a/src/main/java/emu/grasscutter/game/home/HomeWorld.java +++ b/src/main/java/emu/grasscutter/game/home/HomeWorld.java @@ -8,33 +8,57 @@ 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.*; -import java.util.List; +import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify; +import emu.grasscutter.server.packet.send.PacketPlayerChatNotify; +import emu.grasscutter.server.packet.send.PacketPlayerGameTimeNotify; import lombok.Getter; +import java.util.List; +import java.util.function.Consumer; + public class HomeWorld extends World { @Getter private final GameHome home; + @Getter private HomeModuleManager moduleManager; public HomeWorld(GameServer server, Player owner) { super(server, owner); this.home = owner.isOnline() ? owner.getHome() : GameHome.getByUid(owner.getUid()); server.registerHomeWorld(this); + this.refreshModuleManager(); } @Override - public void registerScene(Scene scene) { - this.addAnimalsToScene((HomeScene) scene); - super.registerScene(scene); + public boolean onTick() { + this.moduleManager.tick(); + + if (this.getTickCount() % 10 == 0) { + this.getPlayers().forEach(p -> p.sendPacket(new PacketPlayerGameTimeNotify(p))); + } + + if (this.isInHome(this.getHost()) && this.getTickCount() % 60 == 0) { + this.getHost().updatePlayerGameTime(this.getCurrentWorldTime()); + } + + this.tickCount++; + return false; } - @Override - public void deregisterScene(Scene scene) { - super.deregisterScene(scene); + public void refreshModuleManager() { + if (this.moduleManager != null) { + this.moduleManager.onRemovedModule(); + } + + this.moduleManager = new HomeModuleManager(this); + this.moduleManager.onSetModule(); } - private void addAnimalsToScene(HomeScene scene) { - scene.getSceneItem().getAnimals(scene).forEach(scene::addEntity); + public int getActiveOutdoorSceneId() { + return this.getHost().getCurrentRealmId() + 2000; + } + + public int getActiveIndoorSceneId() { + return this.getSceneById(this.getActiveOutdoorSceneId()).getSceneItem().getRoomSceneId(); } @Override @@ -188,6 +212,12 @@ public class HomeWorld extends World { return this.getPlayers().contains(player); } + public void ifHost(Player hostOrGuest, Consumer ifHost) { + if (this.getHost().equals(hostOrGuest)) { + ifHost.accept(hostOrGuest); + } + } + 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 index aecacb21c..f0da0bf86 100644 --- a/src/main/java/emu/grasscutter/game/home/HomeWorldMPSystem.java +++ b/src/main/java/emu/grasscutter/game/home/HomeWorldMPSystem.java @@ -5,10 +5,7 @@ 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.net.proto.*; import emu.grasscutter.server.event.player.PlayerEnterHomeEvent; import emu.grasscutter.server.event.player.PlayerLeaveHomeEvent; import emu.grasscutter.server.event.player.PlayerTeleportEvent; @@ -215,6 +212,7 @@ public class HomeWorldMPSystem extends BaseGameSystem { player.setCurHomeWorld(myHome); myHome.getHome().onOwnerLogin(player); + player.sendPacket(new PacketPlayerQuitFromHomeNotify(PlayerQuitFromHomeNotifyOuterClass.PlayerQuitFromHomeNotify.QuitReason.BACK_TO_MY_WORLD)); player.sendPacket( new PacketPlayerEnterSceneNotify( player, @@ -263,6 +261,7 @@ public class HomeWorldMPSystem extends BaseGameSystem { victim.setCurHomeWorld(myHome); myHome.getHome().onOwnerLogin(victim); + victim.sendPacket(new PacketPlayerQuitFromHomeNotify(PlayerQuitFromHomeNotifyOuterClass.PlayerQuitFromHomeNotify.QuitReason.KICK_BY_HOST)); victim.sendPacket( new PacketPlayerEnterSceneNotify( victim, diff --git a/src/main/java/emu/grasscutter/game/home/suite/HomeSuiteItem.java b/src/main/java/emu/grasscutter/game/home/suite/HomeSuiteItem.java new file mode 100644 index 000000000..263240452 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/home/suite/HomeSuiteItem.java @@ -0,0 +1,82 @@ +package emu.grasscutter.game.home.suite; + +import dev.morphia.annotations.Entity; +import emu.grasscutter.game.home.HomeMarkPointProtoFactory; +import emu.grasscutter.game.home.SpecialFurnitureType; +import emu.grasscutter.game.world.Position; +import emu.grasscutter.net.proto.HomeFurnitureSuiteDataOuterClass; +import emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass; +import emu.grasscutter.net.proto.HomeMarkPointSuiteDataOuterClass; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.experimental.FieldDefaults; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Objects; + +@Entity +@Builder(builderMethodName = "of") +@Getter +@FieldDefaults(level = AccessLevel.PRIVATE) +public class HomeSuiteItem implements HomeMarkPointProtoFactory { + public static final int SUITE_FURNITURE_ID = 377101; + int guid; + int suiteId; + Position pos; + List includedFurnitureIndexList; + boolean isAllowSummon; + + public static HomeSuiteItem parseFrom(HomeFurnitureSuiteDataOuterClass.HomeFurnitureSuiteData data) { + return HomeSuiteItem.of() + .guid(data.getGuid()) + .suiteId(data.getSuiteId()) + .pos(new Position(data.getSpawnPos())) + .includedFurnitureIndexList(data.getIncludedFurnitureIndexListList()) + .isAllowSummon(data.getIsAllowSummon()) + .build(); + } + + public HomeFurnitureSuiteDataOuterClass.HomeFurnitureSuiteData toProto() { + return HomeFurnitureSuiteDataOuterClass.HomeFurnitureSuiteData.newBuilder() + .setSuiteId(this.suiteId) + .setGuid(this.guid) + .setIsAllowSummon(this.isAllowSummon) + .addAllIncludedFurnitureIndexList(this.includedFurnitureIndexList) + .setSpawnPos(this.pos.toProto()) + .build(); + } + + @Nullable + @Override + public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto() { + return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder() + .setFurnitureId(SUITE_FURNITURE_ID) + .setPos(this.pos.toProto()) + .setFurnitureType(this.getType().getValue()) + .setGuid(this.guid) + .setSuiteData(HomeMarkPointSuiteDataOuterClass.HomeMarkPointSuiteData.newBuilder() + .setSuiteId(this.suiteId) + .build()) + .build(); + } + + @Override + public SpecialFurnitureType getType() { + return SpecialFurnitureType.FurnitureSuite; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + HomeSuiteItem that = (HomeSuiteItem) o; + return suiteId == that.suiteId; + } + + @Override + public int hashCode() { + return Objects.hash(suiteId); + } +} diff --git a/src/main/java/emu/grasscutter/game/home/suite/event/HomeAvatarEvent.java b/src/main/java/emu/grasscutter/game/home/suite/event/HomeAvatarEvent.java new file mode 100644 index 000000000..60a4707f9 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/home/suite/event/HomeAvatarEvent.java @@ -0,0 +1,54 @@ +package emu.grasscutter.game.home.suite.event; + +import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.utils.Utils; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +import java.util.List; +import java.util.Objects; + +@Getter +@FieldDefaults(level = AccessLevel.PRIVATE) +public abstract class HomeAvatarEvent { + final Player homeOwner; + final int eventId; + final int rewardId; + final int avatarId; + final int suiteId; + final int guid; + final int randomPos; + + public HomeAvatarEvent(Player homeOwner, int eventId, int rewardId, int avatarId, int suiteId, int guid) { + this.homeOwner = homeOwner; + this.eventId = eventId; + this.rewardId = rewardId; + this.avatarId = avatarId; + this.suiteId = suiteId; + this.guid = guid; + this.randomPos = this.generateRandomPos(); + } + + public int generateRandomPos() { + return Utils.randomRange(1, 97); + } + + public List giveRewards() { + return List.of(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + HomeAvatarEvent that = (HomeAvatarEvent) o; + return eventId == that.eventId; + } + + @Override + public int hashCode() { + return Objects.hash(eventId); + } +} diff --git a/src/main/java/emu/grasscutter/game/home/suite/event/HomeAvatarRewardEvent.java b/src/main/java/emu/grasscutter/game/home/suite/event/HomeAvatarRewardEvent.java new file mode 100644 index 000000000..651212142 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/home/suite/event/HomeAvatarRewardEvent.java @@ -0,0 +1,37 @@ +package emu.grasscutter.game.home.suite.event; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.net.proto.HomeAvatarRewardEventInfoOuterClass; + +import java.util.List; + +public class HomeAvatarRewardEvent extends HomeAvatarEvent { + public HomeAvatarRewardEvent(Player homeOwner, int eventId, int rewardId, int avatarId, int suiteId, int guid) { + super(homeOwner, eventId, rewardId, avatarId, suiteId, guid); + } + + public HomeAvatarRewardEventInfoOuterClass.HomeAvatarRewardEventInfo toProto() { + return HomeAvatarRewardEventInfoOuterClass.HomeAvatarRewardEventInfo.newBuilder() + .setAvatarId(this.getAvatarId()) + .setEventId(this.getEventId()) + .setGuid(this.getGuid()) + .setSuiteId(this.getSuiteId()) + .setRandomPosition(this.getRandomPos()) + .build(); + } + + @Override + public List giveRewards() { + var data = GameData.getRewardDataMap().get(this.getRewardId()); + if (data == null) { + return List.of(); + } + + var rewards = data.getRewardItemList().stream().map(GameItem::new).toList(); + this.getHomeOwner().getInventory().addItems(rewards, ActionReason.HomeAvatarEventReward); + return rewards; + } +} diff --git a/src/main/java/emu/grasscutter/game/home/suite/event/HomeAvatarSummonEvent.java b/src/main/java/emu/grasscutter/game/home/suite/event/HomeAvatarSummonEvent.java new file mode 100644 index 000000000..961cfe7ab --- /dev/null +++ b/src/main/java/emu/grasscutter/game/home/suite/event/HomeAvatarSummonEvent.java @@ -0,0 +1,36 @@ +package emu.grasscutter.game.home.suite.event; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.proto.HomeAvatarSummonEventInfoOuterClass; +import emu.grasscutter.utils.Utils; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.experimental.FieldDefaults; + +@Getter +@FieldDefaults(level = AccessLevel.PRIVATE) +public class HomeAvatarSummonEvent extends HomeAvatarEvent { + public static final int TIME_LIMIT_SECS = 240; + final int eventOverTime; + + public HomeAvatarSummonEvent(Player homeOwner, int eventId, int rewardId, int avatarId, int suiteId, int guid) { + super(homeOwner, eventId, rewardId, avatarId, suiteId, guid); + + this.eventOverTime = Utils.getCurrentSeconds() + TIME_LIMIT_SECS; + } + + public HomeAvatarSummonEventInfoOuterClass.HomeAvatarSummonEventInfo toProto() { + return HomeAvatarSummonEventInfoOuterClass.HomeAvatarSummonEventInfo.newBuilder() + .setAvatarId(this.getAvatarId()) + .setEventId(this.getEventId()) + .setGuid(this.getGuid()) + .setSuitId(this.getSuiteId()) + .setRandomPosition(this.getRandomPos()) + .setEventOverTime(this.eventOverTime) + .build(); + } + + public boolean isTimeOver() { + return Utils.getCurrentSeconds() > this.eventOverTime; + } +} diff --git a/src/main/java/emu/grasscutter/game/home/suite/event/SuiteEventType.java b/src/main/java/emu/grasscutter/game/home/suite/event/SuiteEventType.java new file mode 100644 index 000000000..8c501f462 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/home/suite/event/SuiteEventType.java @@ -0,0 +1,19 @@ +package emu.grasscutter.game.home.suite.event; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.excels.HomeWorldEventData; + +import javax.annotation.Nullable; + +public enum SuiteEventType { + HOME_AVATAR_REWARD_EVENT, + HOME_AVATAR_SUMMON_EVENT; + + @Nullable + public HomeWorldEventData getEventDataFrom(int avatarId, int suiteId) { + return GameData.getHomeWorldEventDataMap().values().stream() + .filter(data -> data.getEventType() == this && data.getAvatarID() == avatarId && data.getSuiteId() == suiteId) + .findFirst() + .orElse(null); + } +} diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index d4b242d31..5adc13b80 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -950,6 +950,13 @@ public class Player implements PlayerHook, FieldFetch { this.sendPacket(new PacketAvatarGainCostumeNotify(costumeId)); } + public int getCostumeFrom(int avatarId) { + var avatars = this.getAvatars(); + avatars.loadFromDatabase(); + var avatar = avatars.getAvatarById(avatarId); + return avatar == null ? 0 : avatar.getCostume(); + } + public void addPersonalLine(int personalLineId) { this.getPersonalLineList().add(personalLineId); session.getPlayer().getQuestManager().queueEvent(QuestCond.QUEST_COND_PERSONAL_LINE_UNLOCK, personalLineId); diff --git a/src/main/java/emu/grasscutter/game/props/ActionReason.java b/src/main/java/emu/grasscutter/game/props/ActionReason.java index 76a2aed58..57867ed35 100644 --- a/src/main/java/emu/grasscutter/game/props/ActionReason.java +++ b/src/main/java/emu/grasscutter/game/props/ActionReason.java @@ -177,7 +177,8 @@ public enum ActionReason { ChannellerSlabLoopDungeonFirstPassReward(1090), ChannellerSlabLoopDungeonScoreReward(1091), HomeLimitedShopBuy(1092), - HomeCoinCollect(1093); + HomeCoinCollect(1093), + HomeAvatarEventReward(1100); private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); private static final Map stringMap = new HashMap<>(); diff --git a/src/main/java/emu/grasscutter/game/world/World.java b/src/main/java/emu/grasscutter/game/world/World.java index 3b9e01ed0..085e60fe7 100644 --- a/src/main/java/emu/grasscutter/game/world/World.java +++ b/src/main/java/emu/grasscutter/game/world/World.java @@ -39,7 +39,7 @@ public class World implements Iterable { @Getter private boolean timeLocked; private long lastUpdateTime; - @Getter private int tickCount = 0; + @Getter protected int tickCount = 0; @Getter private boolean isPaused = false; @Getter private long currentWorldTime; diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeAvatarRewardEventGetReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeAvatarRewardEventGetReq.java new file mode 100644 index 000000000..6a5482edf --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeAvatarRewardEventGetReq.java @@ -0,0 +1,30 @@ +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.HomeAvatarRewardEventGetReqOuterClass; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketHomeAvatarAllFinishRewardNotify; +import emu.grasscutter.server.packet.send.PacketHomeAvatarRewardEventGetRsp; +import emu.grasscutter.server.packet.send.PacketHomeAvatarRewardEventNotify; + +@Opcodes(PacketOpcodes.HomeAvatarRewardEventGetReq) +public class HandlerHomeAvatarRewardEventGetReq extends PacketHandler { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = HomeAvatarRewardEventGetReqOuterClass.HomeAvatarRewardEventGetReq.parseFrom(payload); + + var player = session.getPlayer(); + var rewardsOrError = player.getCurHomeWorld().getModuleManager().claimAvatarRewards(req.getEventId()); + session.send(new PacketHomeAvatarRewardEventNotify(player)); + session.send(new PacketHomeAvatarAllFinishRewardNotify(player)); + + session.send( + rewardsOrError.map( + gameItems -> new PacketHomeAvatarRewardEventGetRsp(req.getEventId(), gameItems), + integer -> new PacketHomeAvatarRewardEventGetRsp(req.getEventId(), integer) + ) + ); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeAvatarSummonEventReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeAvatarSummonEventReq.java new file mode 100644 index 000000000..c650e0110 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeAvatarSummonEventReq.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.HomeAvatarSummonEventReqOuterClass; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketHomeAvatarSummonEventRsp; + +@Opcodes(PacketOpcodes.HomeAvatarSummonEventReq) +public class HandlerHomeAvatarSummonEventReq extends PacketHandler { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = HomeAvatarSummonEventReqOuterClass.HomeAvatarSummonEventReq.parseFrom(payload); + var moduleManager = session.getPlayer().getCurHomeWorld().getModuleManager(); + var eventOrError = moduleManager.fireAvatarSummonEvent(session.getPlayer(), req.getAvatarId(), req.getGuid(), req.getSuitId()); + session.send(eventOrError.map(PacketHomeAvatarSummonEventRsp::new, PacketHomeAvatarSummonEventRsp::new)); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeAvatarSummonFinishReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeAvatarSummonFinishReq.java new file mode 100644 index 000000000..4027c041a --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeAvatarSummonFinishReq.java @@ -0,0 +1,21 @@ +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.HomeAvatarSummonFinishReqOuterClass; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketHomeAvatarSummonAllEventNotify; +import emu.grasscutter.server.packet.send.PacketHomeAvatarSummonFinishRsp; + +@Opcodes(PacketOpcodes.HomeAvatarSummonFinishReq) +public class HandlerHomeAvatarSummonFinishReq extends PacketHandler { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = HomeAvatarSummonFinishReqOuterClass.HomeAvatarSummonFinishReq.parseFrom(payload); + var player = session.getPlayer(); + player.getCurHomeWorld().getModuleManager().onFinishSummonEvent(req.getEventId()); + session.send(new PacketHomeAvatarSummonAllEventNotify(session.getPlayer())); + session.send(new PacketHomeAvatarSummonFinishRsp(req.getEventId())); + } +} 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 4d6ae5dfa..3befd5b9e 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeEditModeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeEditModeReq.java @@ -1,5 +1,6 @@ package emu.grasscutter.server.packet.recv; +import emu.grasscutter.game.home.HomeScene; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketOpcodes; @@ -31,14 +32,8 @@ public class HandlerHomeChangeEditModeReq extends PacketHandler { session.send(new PacketHomeComfortInfoNotify(session.getPlayer())); if (!req.getIsEnterEditMode()) { - var scene = session.getPlayer().getScene(); - scene.addEntities( - session - .getPlayer() - .getCurHomeWorld() - .getHome() - .getHomeSceneItem(scene.getId()) - .getAnimals(scene)); + var scene = (HomeScene) session.getPlayer().getScene(); + scene.onLeaveEditMode(); } session.send(new PacketHomeChangeEditModeRsp(req.getIsEnterEditMode())); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeModuleReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeModuleReq.java index cff46aab2..f18e5c141 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeModuleReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeChangeModuleReq.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; @@ -19,9 +17,10 @@ public class HandlerHomeChangeModuleReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { HomeChangeModuleReqOuterClass.HomeChangeModuleReq req = - HomeChangeModuleReqOuterClass.HomeChangeModuleReq.parseFrom(payload); + HomeChangeModuleReqOuterClass.HomeChangeModuleReq.parseFrom(payload); - if (!session.getPlayer().getCurHomeWorld().getGuests().isEmpty()) { + var homeWorld = session.getPlayer().getCurHomeWorld(); + if (!homeWorld.getGuests().isEmpty()) { session.send(new PacketHomeChangeModuleRsp()); return; } @@ -33,13 +32,10 @@ public class HandlerHomeChangeModuleReq extends PacketHandler { session.send(new PacketHomeComfortInfoNotify(session.getPlayer())); int realmId = 2000 + req.getTargetModuleId(); + var scene = homeWorld.getSceneById(realmId); + var pos = scene.getScriptManager().getConfig().born_pos; - Scene scene = session.getPlayer().getWorld().getSceneById(realmId); - Position pos = scene.getScriptManager().getConfig().born_pos; - - session - .getPlayer() - .getWorld() - .transferPlayerToScene(session.getPlayer(), realmId, TeleportType.WAYPOINT, pos); + homeWorld.transferPlayerToScene(session.getPlayer(), realmId, TeleportType.WAYPOINT, pos); + homeWorld.refreshModuleManager(); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeEnterEditModeFinishReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeEnterEditModeFinishReq.java index 7890726e0..9f4f8f5ae 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeEnterEditModeFinishReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeEnterEditModeFinishReq.java @@ -1,10 +1,9 @@ package emu.grasscutter.server.packet.recv; -import emu.grasscutter.game.entity.EntityHomeAnimal; +import emu.grasscutter.game.home.HomeScene; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketOpcodes; -import emu.grasscutter.net.proto.VisionTypeOuterClass; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.PacketHomeEnterEditModeFinishRsp; @@ -17,12 +16,8 @@ public class HandlerHomeEnterEditModeFinishReq extends PacketHandler { * This packet is about the edit mode */ - var scene = session.getPlayer().getScene(); - scene.removeEntities( - scene.getEntities().values().stream() - .filter(gameEntity -> gameEntity instanceof EntityHomeAnimal) - .toList(), - VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE); + var scene = (HomeScene) session.getPlayer().getScene(); + scene.onEnterEditModeFinish(); session.send(new PacketHomeEnterEditModeFinishRsp()); } 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 2932a663b..a86e8f32c 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSceneInitFinishReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeSceneInitFinishReq.java @@ -1,6 +1,8 @@ package emu.grasscutter.server.packet.recv; -import emu.grasscutter.net.packet.*; +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.*; @@ -16,16 +18,20 @@ public class HandlerHomeSceneInitFinishReq extends PacketHandler { session.getPlayer().setHasSentInitPacketInHome(true); if (curHomeWorld.getHost().isOnline() - && !curHomeWorld.getHost().equals(session.getPlayer())) { + && !curHomeWorld.getHost().equals(session.getPlayer())) { curHomeWorld - .getHost() - .sendPacket( - new PacketOtherPlayerEnterOrLeaveHomeNotify( - session.getPlayer(), - OtherPlayerEnterHomeNotifyOuterClass.OtherPlayerEnterHomeNotify.Reason.ENTER)); + .getHost() + .sendPacket( + new PacketOtherPlayerEnterOrLeaveHomeNotify( + session.getPlayer(), + OtherPlayerEnterHomeNotifyOuterClass.OtherPlayerEnterHomeNotify.Reason.ENTER)); } } + curHomeWorld.ifHost(session.getPlayer(), player -> { + player.sendPacket(new PacketHomeAvatarRewardEventNotify(player)); + player.sendPacket(new PacketHomeAvatarSummonAllEventNotify(player)); + }); session.send(new PacketHomeMarkPointNotify(session.getPlayer())); session.send(new PacketHomeSceneInitFinishRsp()); 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 2b93ac718..e605dc091 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUpdateArrangementInfoReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUpdateArrangementInfoReq.java @@ -5,10 +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.PacketHomeAvatarTalkFinishInfoNotify; -import emu.grasscutter.server.packet.send.PacketHomeBasicInfoNotify; -import emu.grasscutter.server.packet.send.PacketHomeMarkPointNotify; -import emu.grasscutter.server.packet.send.PacketHomeUpdateArrangementInfoRsp; +import emu.grasscutter.server.packet.send.*; @Opcodes(PacketOpcodes.HomeUpdateArrangementInfoReq) public class HandlerHomeUpdateArrangementInfoReq extends PacketHandler { @@ -22,14 +19,17 @@ public class HandlerHomeUpdateArrangementInfoReq extends PacketHandler { session.getPlayer().getHome().getHomeSceneItem(session.getPlayer().getSceneId()); var roomSceneId = homeScene.getRoomSceneId(); - homeScene.update(req.getSceneArrangementInfo()); + homeScene.update(req.getSceneArrangementInfo(), session.getPlayer()); if (roomSceneId != homeScene.getRoomSceneId()) { session.getPlayer().getHome().onMainHouseChanged(); } + session.getPlayer().getCurHomeWorld().getModuleManager().onUpdateArrangement(); + session.send(new PacketHomeAvatarRewardEventNotify(session.getPlayer())); session.send( new PacketHomeBasicInfoNotify(session.getPlayer(), session.getPlayer().isInEditMode())); session.send(new PacketHomeAvatarTalkFinishInfoNotify(session.getPlayer())); + session.send(new PacketHomeAvatarSummonAllEventNotify(session.getPlayer())); session.send(new PacketHomeMarkPointNotify(session.getPlayer())); session.getPlayer().getHome().save(); diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarAllFinishRewardNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarAllFinishRewardNotify.java new file mode 100644 index 000000000..eda4ae116 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarAllFinishRewardNotify.java @@ -0,0 +1,18 @@ +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.HomeAvatarAllFinishRewardNotifyOuterClass; + +public class PacketHomeAvatarAllFinishRewardNotify extends BasePacket { + public PacketHomeAvatarAllFinishRewardNotify(Player player) { + super(PacketOpcodes.HomeAvatarAllFinishRewardNotify); + + var list = player.getHome().getFinishedRewardEventIdSet(); + if (list != null) { + this.setData(HomeAvatarAllFinishRewardNotifyOuterClass.HomeAvatarAllFinishRewardNotify.newBuilder() + .addAllEventIdList(player.getHome().getFinishedRewardEventIdSet())); + } + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarRewardEventGetRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarRewardEventGetRsp.java new file mode 100644 index 000000000..73aa4d762 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarRewardEventGetRsp.java @@ -0,0 +1,26 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.HomeAvatarRewardEventGetRspOuterClass; + +import java.util.List; + +public class PacketHomeAvatarRewardEventGetRsp extends BasePacket { + public PacketHomeAvatarRewardEventGetRsp(int eventId, List rewards) { + super(PacketOpcodes.HomeAvatarRewardEventGetRsp); + + this.setData(HomeAvatarRewardEventGetRspOuterClass.HomeAvatarRewardEventGetRsp.newBuilder() + .setEventId(eventId) + .addAllItemList(rewards.stream().map(GameItem::toItemParam).toList())); + } + + public PacketHomeAvatarRewardEventGetRsp(int eventId, int retcode) { + super(PacketOpcodes.HomeAvatarRewardEventGetRsp); + + this.setData(HomeAvatarRewardEventGetRspOuterClass.HomeAvatarRewardEventGetRsp.newBuilder() + .setEventId(eventId) + .setRetcode(retcode)); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarRewardEventNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarRewardEventNotify.java new file mode 100644 index 000000000..cea81c2ae --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarRewardEventNotify.java @@ -0,0 +1,12 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; + +public class PacketHomeAvatarRewardEventNotify extends BasePacket { + public PacketHomeAvatarRewardEventNotify(Player homeOwner) { + super(PacketOpcodes.HomeAvatarRewardEventNotify); + this.setData(homeOwner.getCurHomeWorld().getModuleManager().toRewardEventProto()); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarSummonAllEventNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarSummonAllEventNotify.java new file mode 100644 index 000000000..70925d38c --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarSummonAllEventNotify.java @@ -0,0 +1,12 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; + +public class PacketHomeAvatarSummonAllEventNotify extends BasePacket { + public PacketHomeAvatarSummonAllEventNotify(Player homeOwner) { + super(PacketOpcodes.HomeAvatarSummonAllEventNotify); + this.setData(homeOwner.getCurHomeWorld().getModuleManager().toSummonEventProto()); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarSummonEventRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarSummonEventRsp.java new file mode 100644 index 000000000..6c28fb695 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarSummonEventRsp.java @@ -0,0 +1,22 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.game.home.suite.event.HomeAvatarSummonEvent; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.HomeAvatarSummonEventRspOuterClass; + +public class PacketHomeAvatarSummonEventRsp extends BasePacket { + public PacketHomeAvatarSummonEventRsp(HomeAvatarSummonEvent event) { + super(PacketOpcodes.HomeAvatarSummonEventRsp); + + this.setData(HomeAvatarSummonEventRspOuterClass.HomeAvatarSummonEventRsp.newBuilder() + .setEventId(event.getEventId())); + } + + public PacketHomeAvatarSummonEventRsp(int retcode) { + super(PacketOpcodes.HomeAvatarSummonEventRsp); + + this.setData(HomeAvatarSummonEventRspOuterClass.HomeAvatarSummonEventRsp.newBuilder() + .setRetcode(retcode)); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarSummonFinishRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarSummonFinishRsp.java new file mode 100644 index 000000000..66ad749e4 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeAvatarSummonFinishRsp.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.HomeAvatarSummonFinishRspOuterClass; + +public class PacketHomeAvatarSummonFinishRsp extends BasePacket { + public PacketHomeAvatarSummonFinishRsp(int eventId) { + super(PacketOpcodes.HomeAvatarSummonFinishRsp); + + this.setData(HomeAvatarSummonFinishRspOuterClass.HomeAvatarSummonFinishRsp.newBuilder() + .setEventId(eventId)); + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerQuitFromHomeNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerQuitFromHomeNotify.java new file mode 100644 index 000000000..2c5a82332 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerQuitFromHomeNotify.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.PlayerQuitFromHomeNotifyOuterClass; + +public class PacketPlayerQuitFromHomeNotify extends BasePacket { + public PacketPlayerQuitFromHomeNotify(PlayerQuitFromHomeNotifyOuterClass.PlayerQuitFromHomeNotify.QuitReason reason) { + super(PacketOpcodes.PlayerQuitFromHomeNotify); + + this.setData(PlayerQuitFromHomeNotifyOuterClass.PlayerQuitFromHomeNotify.newBuilder() + .setReason(reason)); + } +} diff --git a/src/main/java/emu/grasscutter/utils/Either.java b/src/main/java/emu/grasscutter/utils/Either.java new file mode 100644 index 000000000..b976fdfbd --- /dev/null +++ b/src/main/java/emu/grasscutter/utils/Either.java @@ -0,0 +1,153 @@ +package emu.grasscutter.utils; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; + +public abstract class Either { + private static final class Left extends Either { + private final L value; + + public Left(L value) { + this.value = value; + } + + @Override + public Either mapBoth(Function super L, ? extends U> f1, Function super R, ? extends V> f2) { + return new Left<>(f1.apply(this.value)); + } + + @Override + public T map(Function super L, ? extends T> l, Function super R, ? extends T> r) { + return l.apply(this.value); + } + + @Override + public Either ifLeft(Consumer super L> consumer) { + consumer.accept(this.value); + return this; + } + + @Override + public Either ifRight(Consumer super R> consumer) { + return this; + } + + @Override + public Optional left() { + return Optional.of(this.value); + } + + @Override + public Optional right() { + return Optional.empty(); + } + + @Override + public String toString() { + return "Left[" + this.value + "]"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Left, ?> left = (Left, ?>) o; + return Objects.equals(value, left.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + } + + private static final class Right extends Either { + private final R value; + + public Right(R value) { + this.value = value; + } + + @Override + public Either mapBoth(Function super L, ? extends U> f1, Function super R, ? extends V> f2) { + return new Right<>(f2.apply(this.value)); + } + + @Override + public T map(Function super L, ? extends T> l, Function super R, ? extends T> r) { + return r.apply(this.value); + } + + @Override + public Either ifLeft(Consumer super L> consumer) { + return this; + } + + @Override + public Either ifRight(Consumer super R> consumer) { + consumer.accept(this.value); + return this; + } + + @Override + public Optional left() { + return Optional.empty(); + } + + @Override + public Optional right() { + return Optional.of(this.value); + } + + @Override + public String toString() { + return "Right[" + this.value + "]"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Right, ?> right = (Right, ?>) o; + return Objects.equals(value, right.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + } + + private Either() { + } + + public abstract Either mapBoth(Function super L, ? extends U> f1, Function super R, ? extends V> f2); + + public abstract T map(Function super L, ? extends T> l, Function super R, ? extends T> r); + + public abstract Either ifLeft(Consumer super L> consumer); + + public abstract Either ifRight(Consumer super R> consumer); + + public abstract Optional left(); + + public abstract Optional right(); + + public Either mapLeft(Function super L, ? extends T> l) { + return map(t -> left(l.apply(t)), Either::right); + } + + public Either mapRight(Function super R, ? extends T> l) { + return map(Either::left, t -> right(l.apply(t))); + } + + public static Either left(L value) { + return new Left<>(value); + } + + public static Either right(R value) { + return new Right<>(value); + } +}