From 73c23707b48d591c02ee430e599700ea07580e19 Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Wed, 31 May 2023 21:04:38 -0400 Subject: [PATCH] Fix new avatar weapons being null --- .../emu/grasscutter/game/avatar/Avatar.java | 50 +++++++++---------- .../game/avatar/AvatarStorage.java | 4 ++ .../grasscutter/game/inventory/Inventory.java | 33 ++++++------ .../game/player/BasePlayerManager.java | 5 +- .../emu/grasscutter/game/player/Player.java | 11 +++- .../send/PacketSceneTeamUpdateNotify.java | 2 +- .../java/emu/grasscutter/utils/Utils.java | 28 +++++++++-- 7 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/avatar/Avatar.java b/src/main/java/emu/grasscutter/game/avatar/Avatar.java index c50586430..91500b0e7 100644 --- a/src/main/java/emu/grasscutter/game/avatar/Avatar.java +++ b/src/main/java/emu/grasscutter/game/avatar/Avatar.java @@ -1,34 +1,21 @@ package emu.grasscutter.game.avatar; -import static emu.grasscutter.config.Configuration.GAME_OPTIONS; - import dev.morphia.annotations.*; import emu.grasscutter.GameConstants; import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.OpenConfigEntry; import emu.grasscutter.data.binout.OpenConfigEntry.SkillPointModifier; import emu.grasscutter.data.common.FightPropData; -import emu.grasscutter.data.excels.EquipAffixData; +import emu.grasscutter.data.excels.*; import emu.grasscutter.data.excels.ItemData.WeaponProperty; -import emu.grasscutter.data.excels.ProudSkillData; -import emu.grasscutter.data.excels.avatar.AvatarData; -import emu.grasscutter.data.excels.avatar.AvatarSkillData; -import emu.grasscutter.data.excels.avatar.AvatarSkillDepotData; +import emu.grasscutter.data.excels.avatar.*; import emu.grasscutter.data.excels.avatar.AvatarSkillDepotData.InherentProudSkillOpens; -import emu.grasscutter.data.excels.avatar.AvatarTalentData; -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.reliquary.*; import emu.grasscutter.data.excels.trial.TrialAvatarTemplateData; -import emu.grasscutter.data.excels.weapon.WeaponCurveData; -import emu.grasscutter.data.excels.weapon.WeaponPromoteData; +import emu.grasscutter.data.excels.weapon.*; import emu.grasscutter.database.DatabaseHelper; -import emu.grasscutter.game.entity.EntityAvatar; -import emu.grasscutter.game.entity.EntityWeapon; -import emu.grasscutter.game.inventory.EquipType; -import emu.grasscutter.game.inventory.GameItem; -import emu.grasscutter.game.inventory.ItemType; +import emu.grasscutter.game.entity.*; +import emu.grasscutter.game.inventory.*; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.*; import emu.grasscutter.net.proto.AvatarFetterInfoOuterClass.AvatarFetterInfo; @@ -43,15 +30,14 @@ import emu.grasscutter.net.proto.TrialAvatarInfoOuterClass.TrialAvatarInfo; import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.helpers.ProtoHelper; import it.unimi.dsi.fastutil.ints.*; +import lombok.*; +import org.bson.types.ObjectId; + +import javax.annotation.*; import java.util.*; import java.util.stream.Stream; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; -import lombok.val; -import org.bson.types.ObjectId; + +import static emu.grasscutter.config.Configuration.GAME_OPTIONS; @Entity(value = "avatars", useDiscriminator = false) public class Avatar { @@ -241,10 +227,22 @@ public class Avatar { return this.getEquips().get(slotId); } + /** + * @return The avatar's equipped weapon. + */ + @Nullable public GameItem getWeapon() { return this.getEquipBySlot(EquipType.EQUIP_WEAPON); } + /** + * @return The avatar's equipped weapon. + * @throws NullPointerException If the avatar does not have a weapon. + */ + public GameItem getWeaponNotNull() { + return Objects.requireNonNull(this.getWeapon(), "Avatar does not have a weapon."); + } + protected void setSkillDepot(AvatarSkillDepotData skillDepot) { if (this.skillDepot != null) return; this.skillDepot = skillDepot; // Used while loading this from the database diff --git a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java index ff197f127..b4a918b4e 100644 --- a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java +++ b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java @@ -129,6 +129,8 @@ public class AvatarStorage extends BasePlayerManager implements Iterable } public void loadFromDatabase() { + if (this.isLoaded()) return; + List avatars = DatabaseHelper.getAvatars(getPlayer()); for (Avatar avatar : avatars) { @@ -156,6 +158,8 @@ public class AvatarStorage extends BasePlayerManager implements Iterable this.avatars.put(avatar.getAvatarId(), avatar); this.avatarsGuid.put(avatar.getGuid(), avatar); } + + this.setLoaded(true); } public void postLoad() { diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index 9160d244c..db82991a9 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -1,31 +1,24 @@ package emu.grasscutter.game.inventory; -import static emu.grasscutter.config.Configuration.INVENTORY_LIMITS; - import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.excels.ItemData; import emu.grasscutter.database.DatabaseHelper; -import emu.grasscutter.game.avatar.Avatar; -import emu.grasscutter.game.avatar.AvatarStorage; -import emu.grasscutter.game.player.BasePlayerManager; -import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.game.avatar.*; +import emu.grasscutter.game.player.*; +import emu.grasscutter.game.props.*; import emu.grasscutter.game.props.ItemUseAction.UseItemParams; -import emu.grasscutter.game.props.PlayerProperty; -import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.game.quest.enums.QuestContent; import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam; import emu.grasscutter.server.packet.send.*; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; +import emu.grasscutter.utils.Utils; +import it.unimi.dsi.fastutil.ints.*; +import it.unimi.dsi.fastutil.longs.*; + +import java.util.*; + +import static emu.grasscutter.config.Configuration.INVENTORY_LIMITS; public class Inventory extends BasePlayerManager implements Iterable { private final Long2ObjectMap store; @@ -535,6 +528,11 @@ public class Inventory extends BasePlayerManager implements Iterable { } public void loadFromDatabase() { + if (this.isLoaded()) return; + + // Wait for avatars to load. + Utils.waitFor(this.getPlayer().getAvatars()::isLoaded); + List items = DatabaseHelper.getInventoryItems(getPlayer()); for (GameItem item : items) { @@ -575,6 +573,7 @@ public class Inventory extends BasePlayerManager implements Iterable { // Load avatars after inventory. this.getPlayer().getAvatars().postLoad(); + this.setLoaded(true); } @Override diff --git a/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java b/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java index ffe38a853..cf97f9ecd 100644 --- a/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java +++ b/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java @@ -1,9 +1,12 @@ package emu.grasscutter.game.player; -import lombok.NonNull; +import lombok.*; public abstract class BasePlayerManager { protected final transient Player player; + @Getter + @Setter(AccessLevel.PROTECTED) + protected boolean loaded = false; public BasePlayerManager(@NonNull Player player) { this.player = player; diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index feeacc022..df03e8d65 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -1325,11 +1325,20 @@ public class Player implements PlayerHook, FieldFetch { runner.submit(this::loadBattlePassManager); + // Wait for all tasks to finish. + Utils.waitFor(() -> + this.getAvatars().isLoaded() && + this.getInventory().isLoaded()); + this.getPlayerProgress().setPlayer(this); // Add reference to the player. } + /** + * Invoked when the player selects their avatar. + */ public void onPlayerBorn() { - getQuestManager().onPlayerBorn(); + Grasscutter.getThreadPool().submit( + this.getQuestManager()::onPlayerBorn); } public void onLogin() { diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketSceneTeamUpdateNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketSceneTeamUpdateNotify.java index 6c950e777..644534531 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketSceneTeamUpdateNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketSceneTeamUpdateNotify.java @@ -22,7 +22,7 @@ public class PacketSceneTeamUpdateNotify extends BasePacket { .setSceneId(p.getSceneId()) .setEntityId(entityAvatar.getId()) .setSceneEntityInfo(entityAvatar.toProto()) - .setWeaponGuid(entityAvatar.getAvatar().getWeapon().getGuid()) + .setWeaponGuid(entityAvatar.getAvatar().getWeaponNotNull().getGuid()) .setWeaponEntityId(entityAvatar.getWeaponEntityId()) .setIsPlayerCurAvatar(p.getTeamManager().getCurrentAvatarEntity() == entityAvatar) .setIsOnScene(p.getTeamManager().getCurrentAvatarEntity() == entityAvatar) diff --git a/src/main/java/emu/grasscutter/utils/Utils.java b/src/main/java/emu/grasscutter/utils/Utils.java index 142bc78cf..46f4c422b 100644 --- a/src/main/java/emu/grasscutter/utils/Utils.java +++ b/src/main/java/emu/grasscutter/utils/Utils.java @@ -1,15 +1,16 @@ package emu.grasscutter.utils; -import static emu.grasscutter.utils.FileUtils.getResourcePath; -import static emu.grasscutter.utils.lang.Language.translate; - import emu.grasscutter.Grasscutter; import emu.grasscutter.config.ConfigContainer; import emu.grasscutter.data.DataLoader; import emu.grasscutter.game.world.Position; +import emu.grasscutter.utils.objects.Returnable; import io.javalin.http.Context; import io.netty.buffer.*; import it.unimi.dsi.fastutil.ints.*; +import org.slf4j.Logger; + +import javax.annotation.Nullable; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.*; @@ -17,8 +18,9 @@ import java.time.*; import java.time.temporal.TemporalAdjusters; import java.util.*; import java.util.concurrent.ThreadLocalRandom; -import javax.annotation.Nullable; -import org.slf4j.Logger; + +import static emu.grasscutter.utils.FileUtils.getResourcePath; +import static emu.grasscutter.utils.lang.Language.translate; @SuppressWarnings({"UnusedReturnValue", "BooleanMethodIsAlwaysInverted"}) public final class Utils { @@ -477,4 +479,20 @@ public final class Utils { // Return the request IP. return ctx.ip(); } + + /** + * Waits for the task to return true. + * This will halt the thread until the task returns true. + * + * @param runnable The task to run. + */ + public static void waitFor(Returnable runnable) { + while (!runnable.invoke()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } }