fix: arrangement of main house is duplicated even if player changes module (#2325)

* fix: arrangement of main house is duplicated even if player change module

* removeIf

* Update src/main/java/emu/grasscutter/game/home/GameHome.java

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

---------

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
This commit is contained in:
hamusuke 2023-09-03 00:52:56 +09:00 committed by GitHub
parent decf494234
commit ed97201473
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 126 additions and 52 deletions

View File

@ -12,6 +12,7 @@ import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.net.proto.HomeAvatarTalkFinishInfoOuterClass; import emu.grasscutter.net.proto.HomeAvatarTalkFinishInfoOuterClass;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.*;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.*; import java.util.*;
@ -51,6 +52,7 @@ public class GameHome {
int storedFetterExp; int storedFetterExp;
List<FurnitureMakeSlotItem> furnitureMakeSlotItemList; List<FurnitureMakeSlotItem> furnitureMakeSlotItemList;
ConcurrentHashMap<Integer, HomeSceneItem> sceneMap; ConcurrentHashMap<Integer, HomeSceneItem> sceneMap;
ConcurrentHashMap<Integer, HomeSceneItem> mainHouseMap;
Set<Integer> unlockedHomeBgmList; Set<Integer> unlockedHomeBgmList;
int enterHomeOption; int enterHomeOption;
Map<Integer, Set<Integer>> finishedTalkIdMap; Map<Integer, Set<Integer>> finishedTalkIdMap;
@ -60,6 +62,9 @@ public class GameHome {
if (home == null) { if (home == null) {
home = GameHome.create(uid); home = GameHome.create(uid);
} }
home.fixMainHouseIfOld();
return home; return home;
} }
@ -69,12 +74,25 @@ public class GameHome {
public static GameHome create(Integer uid) { public static GameHome create(Integer uid) {
return GameHome.of() return GameHome.of()
.ownerUid(uid) .ownerUid(uid)
.level(1) .level(1)
.sceneMap(new ConcurrentHashMap<>()) .sceneMap(new ConcurrentHashMap<>())
.unlockedHomeBgmList(new HashSet<>()) .mainHouseMap(new ConcurrentHashMap<>())
.finishedTalkIdMap(new HashMap<>()) .unlockedHomeBgmList(new HashSet<>())
.build(); .finishedTalkIdMap(new HashMap<>())
.build();
}
// Data fixer.
private void fixMainHouseIfOld() {
if (this.getMainHouseMap() == null) {
Grasscutter.getLogger().debug("Player {}'s main house will be deleted due to GC update! (ps. sorry XD)", this.getPlayer().getUid());
this.mainHouseMap = new ConcurrentHashMap<>(); // assign.
}
this.getSceneMap().values().removeIf(homeSceneItem -> homeSceneItem.getSceneId() > 2200);
this.save();
} }
public void save() { public void save() {
@ -82,6 +100,10 @@ public class GameHome {
} }
public HomeSceneItem getHomeSceneItem(int sceneId) { public HomeSceneItem getHomeSceneItem(int sceneId) {
if (sceneId >= 2200) {
return this.getMainHouseItem(this.getPlayer().getCurrentRealmId() + 2000);
}
return sceneMap.computeIfAbsent( return sceneMap.computeIfAbsent(
sceneId, sceneId,
e -> { e -> {
@ -98,8 +120,31 @@ public class GameHome {
}); });
} }
public HomeSceneItem getMainHouseItem(int outdoorSceneId) {
return this.getMainHouseMap().computeIfAbsent(outdoorSceneId, integer -> {
var curHomeSceneItem = this.getHomeSceneItem(outdoorSceneId);
var roomSceneId = curHomeSceneItem.getRoomSceneId();
var defaultItem = GameData.getHomeworldDefaultSaveData().get(roomSceneId);
if (defaultItem == null) {
Grasscutter.getLogger().info("defaultItem == null! returns Liyue style house.");
return HomeSceneItem.parseFrom(GameData.getHomeworldDefaultSaveData().get(2202), 2202); // Liyue style
}
Grasscutter.getLogger().info("Set player {} main house {} to initial setting", this.ownerUid, roomSceneId);
return HomeSceneItem.parseFrom(defaultItem, roomSceneId);
});
}
public void onMainHouseChanged() {
Grasscutter.getLogger().debug("main house changed!");
var outdoor = this.getPlayer().getCurrentRealmId() + 2000;
this.getMainHouseMap().remove(outdoor); // delete main house in current scene.
this.getMainHouseItem(outdoor); // put new main house with default arrangement.
this.save();
}
public void onOwnerLogin(Player player) { public void onOwnerLogin(Player player) {
if (this.player == null) this.player = player; this.player = player; // update player pointer. (prevent offline player from sending packet)
player.getSession().send(new PacketHomeBasicInfoNotify(player, false)); player.getSession().send(new PacketHomeBasicInfoNotify(player, false));
player.getSession().send(new PacketPlayerHomeCompInfoNotify(player)); player.getSession().send(new PacketPlayerHomeCompInfoNotify(player));
player.getSession().send(new PacketHomeComfortInfoNotify(player)); player.getSession().send(new PacketHomeComfortInfoNotify(player));
@ -273,19 +318,19 @@ public class GameHome {
}); });
// Check as realm 5 inside is not in defaults and will be null // Check as realm 5 inside is not in defaults and will be null
if (Objects.nonNull(sceneMap.get(player.getCurrentRealmId() + 2200))) { if (Objects.nonNull(mainHouseMap.get(player.getCurrentRealmId() + 2000))) {
// Indoors avatars // Indoors avatars
sceneMap mainHouseMap
.get(player.getCurrentRealmId() + 2200) .get(player.getCurrentRealmId() + 2000)
.getBlockItems() .getBlockItems()
.forEach( .forEach(
(i, e) -> { (i, e) -> {
e.getDeployNPCList() e.getDeployNPCList()
.forEach( .forEach(
id -> { id -> {
invitedAvatars.add(id.getAvatarId()); invitedAvatars.add(id.getAvatarId());
}); });
}); });
} }
// Add exp to all avatars // Add exp to all avatars

View File

@ -5,6 +5,7 @@ import emu.grasscutter.data.GameData;
import emu.grasscutter.data.binout.HomeworldDefaultSaveData; import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
import emu.grasscutter.data.excels.ItemData; import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.game.world.Position; import emu.grasscutter.game.world.Position;
import emu.grasscutter.net.proto.*; import emu.grasscutter.net.proto.*;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -65,7 +66,7 @@ public class HomeFurnitureItem implements HomeMarkPointProtoFactory {
} }
public ItemData getAsItem() { public ItemData getAsItem() {
return GameData.getItemDataMap().get(this.furnitureId); return this.furnitureId == 0 ? null : GameData.getItemDataMap().get(this.furnitureId);
} }
public int getComfort() { public int getComfort() {

View File

@ -9,6 +9,7 @@ import emu.grasscutter.game.entity.EntityHomeAnimal;
import emu.grasscutter.game.world.Position; import emu.grasscutter.game.world.Position;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.HomeSceneArrangementInfoOuterClass.HomeSceneArrangementInfo; import emu.grasscutter.net.proto.HomeSceneArrangementInfoOuterClass.HomeSceneArrangementInfo;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -62,7 +63,11 @@ public class HomeSceneItem {
this.bornRot = new Position(arrangementInfo.getBornRot()); this.bornRot = new Position(arrangementInfo.getBornRot());
this.djinnPos = new Position(arrangementInfo.getDjinnPos()); this.djinnPos = new Position(arrangementInfo.getDjinnPos());
this.homeBgmId = arrangementInfo.getBgmId(); this.homeBgmId = arrangementInfo.getBgmId();
this.mainHouse = HomeFurnitureItem.parseFrom(arrangementInfo.getMainHouse());
if (!this.isRoom() && arrangementInfo.hasMainHouse()) {
this.mainHouse = HomeFurnitureItem.parseFrom(arrangementInfo.getMainHouse());
}
this.tmpVersion = arrangementInfo.getTmpVersion(); this.tmpVersion = arrangementInfo.getTmpVersion();
} }

View File

@ -8,6 +8,7 @@ import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeChangeModuleReqOuterClass; import emu.grasscutter.net.proto.HomeChangeModuleReqOuterClass;
import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType; import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketHomeAvatarTalkFinishInfoNotify; import emu.grasscutter.server.packet.send.PacketHomeAvatarTalkFinishInfoNotify;
import emu.grasscutter.server.packet.send.PacketHomeChangeModuleRsp; import emu.grasscutter.server.packet.send.PacketHomeChangeModuleRsp;
import emu.grasscutter.server.packet.send.PacketHomeComfortInfoNotify; import emu.grasscutter.server.packet.send.PacketHomeComfortInfoNotify;
@ -20,6 +21,12 @@ public class HandlerHomeChangeModuleReq extends PacketHandler {
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
HomeChangeModuleReqOuterClass.HomeChangeModuleReq req = HomeChangeModuleReqOuterClass.HomeChangeModuleReq req =
HomeChangeModuleReqOuterClass.HomeChangeModuleReq.parseFrom(payload); HomeChangeModuleReqOuterClass.HomeChangeModuleReq.parseFrom(payload);
if (!session.getPlayer().getCurHomeWorld().getGuests().isEmpty()) {
session.send(new PacketHomeChangeModuleRsp());
return;
}
session.getPlayer().setCurrentRealmId(req.getTargetModuleId()); session.getPlayer().setCurrentRealmId(req.getTargetModuleId());
session.send(new PacketHomeAvatarTalkFinishInfoNotify(session.getPlayer())); session.send(new PacketHomeAvatarTalkFinishInfoNotify(session.getPlayer()));
session.send(new PacketHomeChangeModuleRsp(req.getTargetModuleId())); session.send(new PacketHomeChangeModuleRsp(req.getTargetModuleId()));

View File

@ -1,6 +1,8 @@
package emu.grasscutter.server.packet.recv; 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.HomeSceneJumpReqOuterClass; import emu.grasscutter.net.proto.HomeSceneJumpReqOuterClass;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketHomeSceneJumpRsp; import emu.grasscutter.server.packet.send.PacketHomeSceneJumpRsp;
@ -22,7 +24,7 @@ public class HandlerHomeSceneJumpReq extends PacketHandler {
var scene = var scene =
world.getSceneById(req.getIsEnterRoomScene() ? homeScene.getRoomSceneId() : realmId); world.getSceneById(req.getIsEnterRoomScene() ? homeScene.getRoomSceneId() : realmId);
var pos = scene.getScriptManager().getConfig().born_pos; var pos = scene.getScriptManager().getConfig().born_pos;
var rot = home.getSceneMap().get(scene.getId()).getBornRot(); var rot = home.getHomeSceneItem(scene.getId()).getBornRot();
// Make player face correct direction when entering or exiting // Make player face correct direction when entering or exiting
session.getPlayer().getRotation().set(rot); session.getPlayer().getRotation().set(rot);

View File

@ -5,6 +5,8 @@ import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeUpdateArrangementInfoReqOuterClass; import emu.grasscutter.net.proto.HomeUpdateArrangementInfoReqOuterClass;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketHomeBasicInfoNotify;
import emu.grasscutter.server.packet.send.PacketHomeAvatarTalkFinishInfoNotify; import emu.grasscutter.server.packet.send.PacketHomeAvatarTalkFinishInfoNotify;
import emu.grasscutter.server.packet.send.PacketHomeMarkPointNotify; import emu.grasscutter.server.packet.send.PacketHomeMarkPointNotify;
import emu.grasscutter.server.packet.send.PacketHomeUpdateArrangementInfoRsp; import emu.grasscutter.server.packet.send.PacketHomeUpdateArrangementInfoRsp;
@ -20,8 +22,13 @@ public class HandlerHomeUpdateArrangementInfoReq extends PacketHandler {
var homeScene = var homeScene =
session.getPlayer().getHome().getHomeSceneItem(session.getPlayer().getSceneId()); session.getPlayer().getHome().getHomeSceneItem(session.getPlayer().getSceneId());
var roomSceneId = homeScene.getRoomSceneId();
homeScene.update(req.getSceneArrangementInfo()); homeScene.update(req.getSceneArrangementInfo());
if (roomSceneId != homeScene.getRoomSceneId()) {
session.getPlayer().getHome().onMainHouseChanged();
}
session.send(new PacketHomeBasicInfoNotify(session.getPlayer(), session.getPlayer().isInEditMode()));
session.send(new PacketHomeAvatarTalkFinishInfoNotify(session.getPlayer())); session.send(new PacketHomeAvatarTalkFinishInfoNotify(session.getPlayer()));
session.send(new PacketHomeMarkPointNotify(session.getPlayer())); session.send(new PacketHomeMarkPointNotify(session.getPlayer()));

View File

@ -1,7 +1,9 @@
package emu.grasscutter.server.packet.send; package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.*; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.HomeChangeModuleRspOuterClass; import emu.grasscutter.net.proto.HomeChangeModuleRspOuterClass;
import emu.grasscutter.net.proto.RetcodeOuterClass;
public class PacketHomeChangeModuleRsp extends BasePacket { public class PacketHomeChangeModuleRsp extends BasePacket {
@ -16,4 +18,11 @@ public class PacketHomeChangeModuleRsp extends BasePacket {
this.setData(proto); this.setData(proto);
} }
public PacketHomeChangeModuleRsp() {
super(PacketOpcodes.HomeChangeModuleRsp);
this.setData(HomeChangeModuleRspOuterClass.HomeChangeModuleRsp.newBuilder()
.setRetcode(RetcodeOuterClass.Retcode.RET_HOME_HAS_GUEST_VALUE));
}
} }

View File

@ -22,7 +22,7 @@ public class PacketHomeComfortInfoNotify extends BasePacket {
var homeScene = player.getHome().getHomeSceneItem(moduleId + 2000); var homeScene = player.getHome().getHomeSceneItem(moduleId + 2000);
var blockComfortList = var blockComfortList =
homeScene.getBlockItems().values().stream().map(HomeBlockItem::calComfort).toList(); homeScene.getBlockItems().values().stream().map(HomeBlockItem::calComfort).toList();
var homeRoomScene = player.getHome().getHomeSceneItem(homeScene.getRoomSceneId()); var homeRoomScene = player.getHome().getMainHouseItem(moduleId + 2000);
comfortInfoList.add( comfortInfoList.add(
HomeModuleComfortInfoOuterClass.HomeModuleComfortInfo.newBuilder() HomeModuleComfortInfoOuterClass.HomeModuleComfortInfo.newBuilder()

View File

@ -1,10 +1,13 @@
package emu.grasscutter.server.packet.send; package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.home.*; 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.*; import emu.grasscutter.net.packet.*;
import emu.grasscutter.net.proto.*; import emu.grasscutter.net.proto.*;
import java.util.Collection; import java.util.Collection;
import java.util.Set;
public class PacketHomeMarkPointNotify extends BasePacket { public class PacketHomeMarkPointNotify extends BasePacket {
@ -20,38 +23,33 @@ public class PacketHomeMarkPointNotify extends BasePacket {
return; return;
} }
for (var moduleId : owner.getRealmList()) { // send current home mark points.
var homeScene = home.getHomeSceneItem(moduleId + 2000); var moduleId = owner.getCurrentRealmId();
var homeScene = home.getHomeSceneItem(moduleId + 2000);
var mainHouse = home.getMainHouseItem(moduleId + 2000);
Set.of(homeScene, mainHouse).forEach(homeSceneItem -> {
var markPointData = var markPointData =
HomeMarkPointSceneDataOuterClass.HomeMarkPointSceneData.newBuilder() HomeMarkPointSceneDataOuterClass.HomeMarkPointSceneData.newBuilder()
.setModuleId(moduleId) .setModuleId(moduleId)
.setSceneId(moduleId + 2000) .setSceneId(homeSceneItem.getSceneId());
.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());
var marks = if (!homeSceneItem.isRoom()) {
homeScene.getBlockItems().values().stream() var config = world.getSceneById(moduleId + 2000).getScriptManager().getConfig();
.map(HomeBlockItem::getMarkPointProtoFactories) markPointData.setSafePointPos(config == null ? homeSceneItem.getBornPos().toProto() : config.born_pos.toProto())
.flatMap(Collection::stream) .setTeapotSpiritPos(homeSceneItem.getDjinnPos().toProto());
.filter(HomeMarkPointProtoFactory::isProtoConvertible) }
.map(HomeMarkPointProtoFactory::toMarkPointProto)
.toList(); var marks = homeSceneItem.getBlockItems().values().stream()
.map(HomeBlockItem::getMarkPointProtoFactories)
.flatMap(Collection::stream)
.filter(HomeMarkPointProtoFactory::isProtoConvertible)
.map(HomeMarkPointProtoFactory::toMarkPointProto)
.toList();
markPointData.addAllFurnitureList(marks); markPointData.addAllFurnitureList(marks);
proto.addMarkPointDataList(markPointData); proto.addMarkPointDataList(markPointData);
} });
this.setData(proto); this.setData(proto);
} }