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.config.*;
import emu.grasscutter.data.binout.routes.Route;
import emu.grasscutter.data.custom.*;
import emu.grasscutter.data.custom.TrialAvatarActivityCustomData;
import emu.grasscutter.data.custom.TrialAvatarCustomData;
import emu.grasscutter.data.excels.*;
import emu.grasscutter.data.excels.achievement.*;
import emu.grasscutter.data.excels.activity.*;
import emu.grasscutter.data.excels.achievement.AchievementData;
import emu.grasscutter.data.excels.achievement.AchievementGoalData;
import emu.grasscutter.data.excels.activity.ActivityCondExcelConfigData;
import emu.grasscutter.data.excels.activity.ActivityData;
import emu.grasscutter.data.excels.activity.ActivityShopData;
import emu.grasscutter.data.excels.activity.ActivityWatcherData;
import emu.grasscutter.data.excels.avatar.*;
import emu.grasscutter.data.excels.codex.*;
import emu.grasscutter.data.excels.dungeon.*;
import emu.grasscutter.data.excels.giving.*;
import emu.grasscutter.data.excels.monster.*;
import emu.grasscutter.data.excels.quest.*;
import emu.grasscutter.data.excels.reliquary.*;
import emu.grasscutter.data.excels.giving.GivingData;
import emu.grasscutter.data.excels.giving.GivingGroupData;
import emu.grasscutter.data.excels.monster.MonsterCurveData;
import emu.grasscutter.data.excels.monster.MonsterData;
import emu.grasscutter.data.excels.monster.MonsterDescribeData;
import emu.grasscutter.data.excels.monster.MonsterSpecialNameData;
import emu.grasscutter.data.excels.quest.QuestData;
import emu.grasscutter.data.excels.quest.QuestGlobalVarData;
import emu.grasscutter.data.excels.reliquary.ReliquaryAffixData;
import emu.grasscutter.data.excels.reliquary.ReliquaryLevelData;
import emu.grasscutter.data.excels.reliquary.ReliquaryMainPropData;
import emu.grasscutter.data.excels.reliquary.ReliquarySetData;
import emu.grasscutter.data.excels.scene.*;
import emu.grasscutter.data.excels.tower.*;
import emu.grasscutter.data.excels.tower.TowerFloorData;
import emu.grasscutter.data.excels.tower.TowerLevelData;
import emu.grasscutter.data.excels.tower.TowerScheduleData;
import emu.grasscutter.data.excels.trial.*;
import emu.grasscutter.data.excels.weapon.*;
import emu.grasscutter.data.excels.world.*;
import emu.grasscutter.data.excels.weapon.WeaponCurveData;
import emu.grasscutter.data.excels.weapon.WeaponLevelData;
import emu.grasscutter.data.excels.weapon.WeaponPromoteData;
import emu.grasscutter.data.excels.world.WeatherData;
import emu.grasscutter.data.excels.world.WorldAreaData;
import emu.grasscutter.data.excels.world.WorldLevelData;
import emu.grasscutter.data.server.*;
import emu.grasscutter.game.dungeons.DungeonDropEntry;
import emu.grasscutter.game.quest.*;
import emu.grasscutter.game.quest.QuestEncryptionKey;
import emu.grasscutter.game.quest.RewindData;
import emu.grasscutter.game.quest.TeleportData;
import emu.grasscutter.game.quest.enums.QuestCond;
import emu.grasscutter.game.world.GroupReplacementData;
import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.*;
import lombok.Getter;
import lombok.Setter;
import lombok.val;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.util.*;
import javax.annotation.Nullable;
import lombok.*;
@SuppressWarnings({"unused", "MismatchedQueryAndUpdateOfCollection"})
public final class GameData {
@@ -265,6 +289,10 @@ public final class GameData {
private static final Int2ObjectMap<HomeWorldLevelData> homeWorldLevelDataMap =
new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<HomeWorldNPCData> homeWorldNPCDataMap =
new Int2ObjectOpenHashMap<>();
@Getter
private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap =
new Int2ObjectOpenHashMap<>();

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

View File

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

View File

@@ -11,12 +11,24 @@ import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.FieldDefaults;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import java.util.stream.Collectors;
@Entity
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
@Builder(builderMethodName = "of")
public class HomeFurnitureItem {
public class HomeFurnitureItem implements HomeMarkPointProtoFactory {
public static final int PAIMON_FURNITURE_ID = 368134;
public static final int TELEPORT_FURNITURE_ID = 373501;
public static final Set<Integer> APARTMENT_FURNITURE_ID_SET = GameData.getItemDataMap().values()
.stream()
.filter(itemData -> itemData.getSpecialFurnitureType() == SpecialFurnitureType.Apartment)
.map(ItemData::getId)
.collect(Collectors.toUnmodifiableSet());
int furnitureId;
int guid;
int parentFurnitureIndex;
@@ -56,17 +68,6 @@ public class HomeFurnitureItem {
.build();
}
public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto(
int type) {
return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
.setFurnitureId(furnitureId)
.setGuid(guid)
.setFurnitureType(type)
.setPos(spawnPos.toProto())
// TODO NPC and farm
.build();
}
public ItemData getAsItem() {
return GameData.getItemDataMap().get(this.furnitureId);
}
@@ -79,4 +80,29 @@ public class HomeFurnitureItem {
}
return item.getComfort();
}
@Nullable
@Override
public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto() {
var type = this.adjustByFurnitureId();
if (type == SpecialFurnitureType.NOT_SPECIAL) {
return null;
}
return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
.setFurnitureId(this.furnitureId)
.setFurnitureType(type.getValue())
.setPos(this.spawnPos.toProto())
.setGuid(this.guid)
.build();
}
@Override
public SpecialFurnitureType adjustByFurnitureId() {
return switch (this.furnitureId) {
case PAIMON_FURNITURE_ID -> SpecialFurnitureType.Paimon;
case TELEPORT_FURNITURE_ID -> SpecialFurnitureType.TeleportPoint;
default -> APARTMENT_FURNITURE_ID_SET.contains(this.furnitureId) ? SpecialFurnitureType.Apartment : SpecialFurnitureType.NOT_SPECIAL;
};
}
}

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;
import dev.morphia.annotations.Entity;
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.world.Position;
import emu.grasscutter.net.proto.HomeMarkPointFurnitureDataOuterClass;
import emu.grasscutter.net.proto.HomeMarkPointNPCDataOuterClass;
import emu.grasscutter.net.proto.HomeNpcDataOuterClass;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.FieldDefaults;
import org.jetbrains.annotations.Nullable;
@Entity
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
@Builder(builderMethodName = "of")
public class HomeNPCItem {
public class HomeNPCItem implements HomeMarkPointProtoFactory {
transient int furnitureId;
int avatarId;
Position spawnPos;
Position spawnRot;
@@ -20,19 +25,52 @@ public class HomeNPCItem {
public static HomeNPCItem parseFrom(HomeNpcDataOuterClass.HomeNpcData homeNpcData) {
return HomeNPCItem.of()
.avatarId(homeNpcData.getAvatarId())
.spawnPos(new Position(homeNpcData.getSpawnPos()))
.spawnRot(new Position(homeNpcData.getSpawnRot()))
.costumeId(homeNpcData.getCostumeId())
.build();
.avatarId(homeNpcData.getAvatarId())
.spawnPos(new Position(homeNpcData.getSpawnPos()))
.spawnRot(new Position(homeNpcData.getSpawnRot()))
.costumeId(homeNpcData.getCostumeId())
.build();
}
public HomeNpcDataOuterClass.HomeNpcData toProto() {
return HomeNpcDataOuterClass.HomeNpcData.newBuilder()
.setAvatarId(avatarId)
.setSpawnPos(spawnPos.toProto())
.setSpawnRot(spawnRot.toProto())
.setCostumeId(costumeId)
.build();
.setAvatarId(avatarId)
.setSpawnPos(spawnPos.toProto())
.setSpawnRot(spawnRot.toProto())
.setCostumeId(costumeId)
.build();
}
public int getFurnitureId() {
if (this.furnitureId == 0) {
var data = GameData.getHomeWorldNPCDataMap().get(this.avatarId);
this.furnitureId = data == null ? -1 : data.getFurnitureID();
}
return this.furnitureId;
}
@Nullable
@Override
public HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData toMarkPointProto() {
return HomeMarkPointFurnitureDataOuterClass.HomeMarkPointFurnitureData.newBuilder()
.setFurnitureId(this.getFurnitureId())
.setFurnitureType(this.getType().getValue())
.setPos(this.spawnPos.toProto())
.setNpcData(HomeMarkPointNPCDataOuterClass.HomeMarkPointNPCData.newBuilder()
.setAvatarId(this.avatarId)
.setCostumeId(this.costumeId)
.build())
.build();
}
@Override
public SpecialFurnitureType getType() {
return SpecialFurnitureType.NPC;
}
@Override
public boolean isProtoConvertible() {
return this.getFurnitureId() > 0;
}
}

View File

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

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