feat: add more home mark point (#2323)

This commit is contained in:
hamusuke
2023-08-31 08:32:47 +09:00
committed by GitHub
parent 7049cfdb58
commit e8f4949836
10 changed files with 257 additions and 54 deletions

View File

@@ -4,33 +4,57 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.*; import emu.grasscutter.data.binout.*;
import emu.grasscutter.data.binout.config.*; import emu.grasscutter.data.binout.config.*;
import emu.grasscutter.data.binout.routes.Route; 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.*;
import emu.grasscutter.data.excels.achievement.*; import emu.grasscutter.data.excels.achievement.AchievementData;
import emu.grasscutter.data.excels.activity.*; 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.avatar.*;
import emu.grasscutter.data.excels.codex.*; import emu.grasscutter.data.excels.codex.*;
import emu.grasscutter.data.excels.dungeon.*; import emu.grasscutter.data.excels.dungeon.*;
import emu.grasscutter.data.excels.giving.*; import emu.grasscutter.data.excels.giving.GivingData;
import emu.grasscutter.data.excels.monster.*; import emu.grasscutter.data.excels.giving.GivingGroupData;
import emu.grasscutter.data.excels.quest.*; import emu.grasscutter.data.excels.monster.MonsterCurveData;
import emu.grasscutter.data.excels.reliquary.*; 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.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.trial.*;
import emu.grasscutter.data.excels.weapon.*; import emu.grasscutter.data.excels.weapon.WeaponCurveData;
import emu.grasscutter.data.excels.world.*; 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.data.server.*;
import emu.grasscutter.game.dungeons.DungeonDropEntry; 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.quest.enums.QuestCond;
import emu.grasscutter.game.world.GroupReplacementData; import emu.grasscutter.game.world.GroupReplacementData;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.*; 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.lang.reflect.Field;
import java.util.*; import java.util.*;
import javax.annotation.Nullable;
import lombok.*;
@SuppressWarnings({"unused", "MismatchedQueryAndUpdateOfCollection"}) @SuppressWarnings({"unused", "MismatchedQueryAndUpdateOfCollection"})
public final class GameData { public final class GameData {
@@ -265,6 +289,10 @@ public final class GameData {
private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap = private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap =
new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<HomeWorldNPCData> homeWorldNPCDataMap =
new Int2ObjectOpenHashMap<>();
@Getter @Getter
private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap = private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap =
new Int2ObjectOpenHashMap<>(); new Int2ObjectOpenHashMap<>();

View File

@@ -0,0 +1,35 @@
package emu.grasscutter.data.excels;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.inventory.ItemQuality;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
import java.util.List;
@ResourceType(name = "HomeWorldNPCExcelConfigData.json")
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class HomeWorldNPCData extends GameResource {
int furnitureID;
int avatarID;
@SerializedName(value = "npcId", alternate = {"HDLJMOGHICL"})
int npcId;
@SerializedName(value = "talkIdList", alternate = {"CKMCLCNIBLD"})
List<Integer> talkIdList;
@SerializedName(value = "isTalkRandomly", alternate = {"HPJMMEBNMAI"})
boolean isTalkRandomly;
@SerializedName(value = "npcQuality", alternate = {"BHJOIKFHIBD"})
ItemQuality npcQuality;
@SerializedName(value = "titleTextMapHash", alternate = {"GNMAIEGCFPO"})
long titleTextMapHash;
long descTextMapHash;
@Override
public int getId() {
return this.avatarID;
}
}

View File

@@ -4,6 +4,7 @@ import com.google.gson.annotations.SerializedName;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.ItemUseData; import emu.grasscutter.data.common.ItemUseData;
import emu.grasscutter.game.home.SpecialFurnitureType;
import emu.grasscutter.game.inventory.EquipType; import emu.grasscutter.game.inventory.EquipType;
import emu.grasscutter.game.inventory.ItemType; import emu.grasscutter.game.inventory.ItemType;
import emu.grasscutter.game.inventory.MaterialType; import emu.grasscutter.game.inventory.MaterialType;
@@ -13,10 +14,11 @@ import emu.grasscutter.game.props.ItemUseOp;
import emu.grasscutter.game.props.ItemUseTarget; import emu.grasscutter.game.props.ItemUseTarget;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.Getter;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import lombok.Getter;
@ResourceType( @ResourceType(
name = { name = {
@@ -86,6 +88,7 @@ public class ItemData extends GameResource {
private int comfort; private int comfort;
private List<Integer> furnType; private List<Integer> furnType;
private List<Integer> furnitureGadgetID; private List<Integer> furnitureGadgetID;
private SpecialFurnitureType specialFurnitureType = SpecialFurnitureType.NOT_SPECIAL;
@SerializedName( @SerializedName(
value = "roomSceneId", value = "roomSceneId",

View File

@@ -4,12 +4,15 @@ import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id; import dev.morphia.annotations.Id;
import emu.grasscutter.data.binout.HomeworldDefaultSaveData; import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
import emu.grasscutter.net.proto.HomeBlockArrangementInfoOuterClass.HomeBlockArrangementInfo; import emu.grasscutter.net.proto.HomeBlockArrangementInfoOuterClass.HomeBlockArrangementInfo;
import java.util.List;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;
@Entity @Entity
@Data @Data
@Builder(builderMethodName = "of") @Builder(builderMethodName = "of")
@@ -77,6 +80,8 @@ public class HomeBlockItem {
.setIsUnlocked(unlocked) .setIsUnlocked(unlocked)
.setComfortValue(calComfort()); .setComfortValue(calComfort());
this.reassignIfNull();
this.deployFurnitureList.forEach(f -> proto.addDeployFurniureList(f.toProto())); this.deployFurnitureList.forEach(f -> proto.addDeployFurniureList(f.toProto()));
this.persistentFurnitureList.forEach(f -> proto.addPersistentFurnitureList(f.toProto())); this.persistentFurnitureList.forEach(f -> proto.addPersistentFurnitureList(f.toProto()));
this.deployAnimalList.forEach(f -> proto.addDeployAnimalList(f.toProto())); this.deployAnimalList.forEach(f -> proto.addDeployAnimalList(f.toProto()));
@@ -84,4 +89,26 @@ public class HomeBlockItem {
return proto.build(); return proto.build();
} }
// TODO add more types (farm field and suite)
public List<? extends HomeMarkPointProtoFactory> getMarkPointProtoFactories() {
this.reassignIfNull();
return Stream.of(this.deployFurnitureList, this.persistentFurnitureList, this.deployNPCList).flatMap(Collection::stream).toList();
}
public void reassignIfNull() {
if (this.deployFurnitureList == null) {
this.deployFurnitureList = List.of();
}
if (this.persistentFurnitureList == null) {
this.persistentFurnitureList = List.of();
}
if (this.deployAnimalList == null) {
this.deployAnimalList = List.of();
}
if (this.deployNPCList == null) {
this.deployNPCList = List.of();
}
}
} }

View File

@@ -11,12 +11,24 @@ import lombok.AccessLevel;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import java.util.stream.Collectors;
@Entity @Entity
@Data @Data
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
@Builder(builderMethodName = "of") @Builder(builderMethodName = "of")
public class HomeFurnitureItem { public class HomeFurnitureItem implements HomeMarkPointProtoFactory {
public static final int PAIMON_FURNITURE_ID = 368134;
public static final int TELEPORT_FURNITURE_ID = 373501;
public static final Set<Integer> APARTMENT_FURNITURE_ID_SET = GameData.getItemDataMap().values()
.stream()
.filter(itemData -> itemData.getSpecialFurnitureType() == SpecialFurnitureType.Apartment)
.map(ItemData::getId)
.collect(Collectors.toUnmodifiableSet());
int furnitureId; int furnitureId;
int guid; int guid;
int parentFurnitureIndex; int parentFurnitureIndex;
@@ -56,17 +68,6 @@ public class HomeFurnitureItem {
.build(); .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() { public ItemData getAsItem() {
return GameData.getItemDataMap().get(this.furnitureId); return GameData.getItemDataMap().get(this.furnitureId);
} }
@@ -79,4 +80,29 @@ public class HomeFurnitureItem {
} }
return item.getComfort(); 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;
};
}
} }

View File

@@ -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;
}
}

View File

@@ -1,18 +1,23 @@
package emu.grasscutter.game.home; package emu.grasscutter.game.home;
import dev.morphia.annotations.Entity; import dev.morphia.annotations.Entity;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.world.Position; 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 emu.grasscutter.net.proto.HomeNpcDataOuterClass;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import org.jetbrains.annotations.Nullable;
@Entity @Entity
@Data @Data
@FieldDefaults(level = AccessLevel.PRIVATE) @FieldDefaults(level = AccessLevel.PRIVATE)
@Builder(builderMethodName = "of") @Builder(builderMethodName = "of")
public class HomeNPCItem { public class HomeNPCItem implements HomeMarkPointProtoFactory {
transient int furnitureId;
int avatarId; int avatarId;
Position spawnPos; Position spawnPos;
Position spawnRot; Position spawnRot;
@@ -35,4 +40,37 @@ public class HomeNPCItem {
.setCostumeId(costumeId) .setCostumeId(costumeId)
.build(); .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;
}
} }

View File

@@ -6,13 +6,14 @@ import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.HomeworldDefaultSaveData; import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
import emu.grasscutter.game.world.Position; import emu.grasscutter.game.world.Position;
import emu.grasscutter.net.proto.HomeSceneArrangementInfoOuterClass.HomeSceneArrangementInfo; import emu.grasscutter.net.proto.HomeSceneArrangementInfoOuterClass.HomeSceneArrangementInfo;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.experimental.FieldDefaults; import lombok.experimental.FieldDefaults;
import java.util.Map;
import java.util.stream.Collectors;
@Entity @Entity
@Data @Data
@Builder(builderMethodName = "of") @Builder(builderMethodName = "of")
@@ -64,12 +65,16 @@ public class HomeSceneItem {
} }
public int getRoomSceneId() { public int getRoomSceneId() {
if (mainHouse == null || mainHouse.getAsItem() == null) { if (this.isRoom()) {
return 0; return 0;
} }
return mainHouse.getAsItem().getRoomSceneId(); return mainHouse.getAsItem().getRoomSceneId();
} }
public boolean isRoom() {
return mainHouse == null || mainHouse.getAsItem() == null;
}
public int calComfort() { public int calComfort() {
return this.blockItems.values().stream().mapToInt(HomeBlockItem::calComfort).sum(); return this.blockItems.values().stream().mapToInt(HomeBlockItem::calComfort).sum();
} }

View File

@@ -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;
}
}

View File

@@ -1,11 +1,13 @@
package emu.grasscutter.server.packet.send; package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.home.HomeBlockItem; import emu.grasscutter.game.home.HomeBlockItem;
import emu.grasscutter.game.home.HomeMarkPointProtoFactory;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeMarkPointNotifyOuterClass; import emu.grasscutter.net.proto.HomeMarkPointNotifyOuterClass;
import emu.grasscutter.net.proto.HomeMarkPointSceneDataOuterClass; import emu.grasscutter.net.proto.HomeMarkPointSceneDataOuterClass;
import emu.grasscutter.net.proto.VectorOuterClass;
import java.util.Collection; import java.util.Collection;
@@ -15,8 +17,9 @@ public class PacketHomeMarkPointNotify extends BasePacket {
super(PacketOpcodes.HomeMarkPointNotify); super(PacketOpcodes.HomeMarkPointNotify);
var proto = HomeMarkPointNotifyOuterClass.HomeMarkPointNotify.newBuilder(); var proto = HomeMarkPointNotifyOuterClass.HomeMarkPointNotify.newBuilder();
var owner = player.getCurHomeWorld().getHost(); var world = player.getCurHomeWorld();
var home = player.getCurHomeWorld().getHome(); var owner = world.getHost();
var home = world.getHome();
if (owner.getRealmList() == null) { if (owner.getRealmList() == null) {
return; return;
@@ -29,17 +32,14 @@ public class PacketHomeMarkPointNotify extends BasePacket {
HomeMarkPointSceneDataOuterClass.HomeMarkPointSceneData.newBuilder() HomeMarkPointSceneDataOuterClass.HomeMarkPointSceneData.newBuilder()
.setModuleId(moduleId) .setModuleId(moduleId)
.setSceneId(moduleId + 2000) .setSceneId(moduleId + 2000)
.setSafePointPos(homeScene.getBornPos().toProto()) .setSafePointPos(homeScene.isRoom() ? VectorOuterClass.Vector.newBuilder().build() : world.getSceneById(moduleId + 2000).getScriptManager().getConfig().born_pos.toProto())
.setTeapotSpiritPos(homeScene.getDjinnPos().toProto()); .setTeapotSpiritPos(homeScene.isRoom() ? VectorOuterClass.Vector.newBuilder().build() : homeScene.getDjinnPos().toProto());
// Now it only supports the teleport point var marks = homeScene.getBlockItems().values().stream()
// TODO add more types .map(HomeBlockItem::getMarkPointProtoFactories)
var marks =
homeScene.getBlockItems().values().stream()
.map(HomeBlockItem::getDeployFurnitureList)
.flatMap(Collection::stream) .flatMap(Collection::stream)
.filter(i -> i.getFurnitureId() == 373501) .filter(HomeMarkPointProtoFactory::isProtoConvertible)
.map(x -> x.toMarkPointProto(3)) .map(HomeMarkPointProtoFactory::toMarkPointProto)
.toList(); .toList();
markPointData.addAllFurnitureList(marks); markPointData.addAllFurnitureList(marks);