Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: NPE related to teapot when player logs in. #2429

Merged
merged 3 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions src/main/java/emu/grasscutter/game/home/GameHome.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@
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 java.util.stream.Stream;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.FieldDefaults;

@Entity(value = "homes", useDiscriminator = false)
@Data
Expand Down Expand Up @@ -181,6 +182,7 @@ public void onMainHouseChanged() {

public void onOwnerLogin(Player player) {
this.player = player; // update player pointer. (prevent offline player from sending packet)
this.fixModuleIdIfInvalid();
player.getSession().send(new PacketHomeBasicInfoNotify(player, false));
player.getSession().send(new PacketPlayerHomeCompInfoNotify(player));
player.getSession().send(new PacketHomeComfortInfoNotify(player));
Expand All @@ -194,6 +196,25 @@ public void onOwnerLogin(Player player) {
player.getSession().send(new PacketHomeResourceNotify(player));
}

private void fixModuleIdIfInvalid() {
if (this.player.hasSentLoginPackets() || this.player.getRealmList() == null) {
return;
}

if (this.player.getRealmList().isEmpty()) {
this.player.setRealmList(null);
return;
}

if (this.player.getCurrentRealmId() <= 0 || !this.player.getCurHomeWorld().isRealmIdValid()) {
int firstRId = this.player.getRealmList().iterator().next();
this.player.setCurrentRealmId(firstRId);
Grasscutter.getLogger().info("Set player {}'s current realm id to {} cuz the id is invalid.", this.player.getUid(), firstRId);
}

this.player.getCurHomeWorld().refreshModuleManager(); // Apply module id fix.
}

public void onPlayerChangedAvatarCostume(Avatar avatar) {
var world = this.player.getServer().getHomeWorldOrCreate(this.player);
world.broadcastPacket(
Expand Down
161 changes: 93 additions & 68 deletions src/main/java/emu/grasscutter/game/home/HomeModuleManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,24 @@
import emu.grasscutter.net.proto.RetcodeOuterClass;
import emu.grasscutter.server.packet.send.PacketHomeAvatarSummonAllEventNotify;
import emu.grasscutter.utils.Either;
import java.util.*;
import java.util.stream.Stream;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.FieldDefaults;

import javax.annotation.Nullable;
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;
@Nullable
final HomeScene outdoor;
@Nullable
HomeScene indoor;
final List<HomeAvatarRewardEvent> rewardEvents;
final List<HomeAvatarSummonEvent> summonEvents;
Expand All @@ -45,8 +49,14 @@ public void tick() {
return;
}

this.outdoor.onTick();
this.indoor.onTick();
if (this.outdoor != null) {
this.outdoor.onTick();
}

if (this.indoor != null) {
this.indoor.onTick();
}

this.summonEvents.removeIf(HomeAvatarSummonEvent::isTimeOver);
}

Expand All @@ -66,44 +76,45 @@ public void onUpdateArrangement() {
private void fireAllAvatarRewardEvents() {
this.rewardEvents.clear();
var allBlockItems =
Stream.of(this.getOutdoorSceneItem(), this.getIndoorSceneItem())
.map(HomeSceneItem::getBlockItems)
.map(Map::values)
.flatMap(Collection::stream)
.toList();
Stream.of(this.getOutdoorSceneItem(), this.getIndoorSceneItem())
.filter(Objects::nonNull)
.map(HomeSceneItem::getBlockItems)
.map(Map::values)
.flatMap(Collection::stream)
.toList();

var suites =
allBlockItems.stream()
.map(HomeBlockItem::getSuiteList)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.distinct()
.toList();
allBlockItems.stream()
.map(HomeBlockItem::getSuiteList)
.filter(Objects::nonNull)
.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()));
});
.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();
Expand All @@ -113,14 +124,15 @@ private void fireAllAvatarRewardEvents() {

private void cancelSummonEventsIfAvatarLeave() {
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();
Stream.of(this.getOutdoorSceneItem(), this.getIndoorSceneItem())
.filter(Objects::nonNull)
.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()));
}
Expand All @@ -143,15 +155,15 @@ public Either<List<GameItem>, Integer> claimAvatarRewards(int eventId) {
}

public Either<HomeAvatarSummonEvent, Integer> fireAvatarSummonEvent(
Player owner, int avatarId, int guid, int suiteId) {
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);
((HomeScene) owner.getScene())
hamusuke0323 marked this conversation as resolved.
Show resolved Hide resolved
.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);
Expand All @@ -173,8 +185,8 @@ public Either<HomeAvatarSummonEvent, Integer> fireAvatarSummonEvent(
}

var event =
new HomeAvatarSummonEvent(
owner, eventData.getId(), eventData.getRewardID(), avatarId, suiteId, guid);
new HomeAvatarSummonEvent(
owner, eventData.getId(), eventData.getRewardID(), avatarId, suiteId, guid);
this.summonEvents.add(event);
owner.sendPacket(new PacketHomeAvatarSummonAllEventNotify(owner));
return Either.left(event);
Expand All @@ -190,41 +202,49 @@ public HomeAvatarRewardEventNotifyOuterClass.HomeAvatarRewardEventNotify toRewar
notify.setRewardEvent(this.rewardEvents.get(0).toProto()).setIsEventTrigger(true);

notify.addAllPendingList(
this.rewardEvents.subList(1, this.rewardEvents.size()).stream()
.map(HomeAvatarRewardEvent::toProto)
.toList());
this.rewardEvents.subList(1, this.rewardEvents.size()).stream()
.map(HomeAvatarRewardEvent::toProto)
.toList());
}

return notify.build();
}

public HomeAvatarSummonAllEventNotifyOuterClass.HomeAvatarSummonAllEventNotify
toSummonEventProto() {
toSummonEventProto() {
hamusuke0323 marked this conversation as resolved.
Show resolved Hide resolved
return HomeAvatarSummonAllEventNotifyOuterClass.HomeAvatarSummonAllEventNotify.newBuilder()
.addAllSummonEventList(
this.summonEvents.stream().map(HomeAvatarSummonEvent::toProto).toList())
.build();
.addAllSummonEventList(
this.summonEvents.stream().map(HomeAvatarSummonEvent::toProto).toList())
.build();
}

public boolean isInRewardEvent(int avatarId) {
return this.rewardEvents.stream().anyMatch(e -> e.getAvatarId() == avatarId);
}

@Nullable
public HomeSceneItem getOutdoorSceneItem() {
return this.outdoor.getSceneItem();
return this.outdoor == null ? null : this.outdoor.getSceneItem();
}

@Nullable
public HomeSceneItem getIndoorSceneItem() {
return this.indoor.getSceneItem();
return this.indoor == null ? null : this.indoor.getSceneItem();
}

public void onSetModule() {
if (this.moduleId == 0) {
return;
}

this.outdoor.addEntities(this.getOutdoorSceneItem().getAnimals(this.outdoor));
this.indoor.addEntities(this.getIndoorSceneItem().getAnimals(this.indoor));
if (this.outdoor != null) {
this.outdoor.addEntities(this.getOutdoorSceneItem().getAnimals(this.outdoor));
}

if (this.indoor != null) {
this.indoor.addEntities(this.getIndoorSceneItem().getAnimals(this.indoor));
}

this.fireAllAvatarRewardEvents();
}

Expand All @@ -233,7 +253,12 @@ public void onRemovedModule() {
return;
}

this.outdoor.getEntities().clear();
this.indoor.getEntities().clear();
if (this.outdoor != null) {
this.outdoor.getEntities().clear();
}

if (this.indoor != null) {
this.indoor.getEntities().clear();
}
}
}
16 changes: 10 additions & 6 deletions src/main/java/emu/grasscutter/game/home/HomeWorld.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
import emu.grasscutter.data.GameData;
import emu.grasscutter.game.entity.EntityTeam;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.world.World;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.ChatInfoOuterClass;
import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify;
import emu.grasscutter.server.packet.send.PacketPlayerChatNotify;
import emu.grasscutter.server.packet.send.PacketPlayerGameTimeNotify;
import lombok.Getter;

import javax.annotation.Nullable;
import java.util.List;
import java.util.function.Consumer;
import lombok.Getter;

@Getter
public class HomeWorld extends World {
Expand Down Expand Up @@ -66,7 +67,7 @@ public int getActiveIndoorSceneId() {
}

public boolean isRealmIdValid() {
return this.getHost().getCurrentRealmId() > 0;
return this.getSceneById(this.getHost().getCurrentRealmId() + 2000) != null;
}

@Override
Expand Down Expand Up @@ -147,11 +148,13 @@ public synchronized void removePlayer(Player player) {
player.setWorld(null);

// Remove from scene
Scene scene = this.getSceneById(player.getSceneId());
scene.removePlayer(player);
var scene = this.getSceneById(player.getSceneId());
if (scene != null) {
scene.removePlayer(player);
}

// Info packet for other players
if (this.getPlayers().size() > 0) {
if (!this.getPlayers().isEmpty()) {
this.updatePlayerInfos(player);
}

Expand All @@ -167,6 +170,7 @@ public synchronized void removePlayer(Player player) {
}

@Override
@Nullable
public HomeScene getSceneById(int sceneId) {
var scene = this.getScenes().get(sceneId);
if (scene instanceof HomeScene homeScene) {
Expand Down
13 changes: 10 additions & 3 deletions src/main/java/emu/grasscutter/game/home/HomeWorldMPSystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,18 @@ public void enterHome(Player requester, Player owner, int teleportPoint, boolean

int realmId = 2000 + owner.getCurrentRealmId();
var item = targetHome.getHomeSceneItem(realmId);
var scene = world.getSceneById(realmId);
targetHome.save();
var pos =

Position pos;
if (scene != null) {
pos =
toSafe
? world.getSceneById(realmId).getScriptManager().getConfig().born_pos
: item.getBornPos();
? scene.getScriptManager().getConfig().born_pos
: item.getBornPos();
} else {
pos = item.getBornPos();
}

if (teleportPoint != 0) {
var target = item.getTeleportPointPos(teleportPoint);
Expand Down
Loading
Loading