From 15749c8ad7ed6bcd0ed2830e18bf7ae3fb5999b1 Mon Sep 17 00:00:00 2001 From: Kam Date: Wed, 11 Mar 2026 21:42:27 -0400 Subject: [PATCH] Profile Sync Quest Data Crash Fix --- .../npcs/controllers/ProfileController.java | 11 ++++ .../npcs/controllers/SyncController.java | 2 + .../kamkeel/npcs/network/PacketHandler.java | 1 + .../npcs/network/enums/EnumDataPacket.java | 3 + .../data/ProfileSharedQuestPacket.java | 57 +++++++++++++++++++ .../npcs/client/ClientCacheHandler.java | 1 + .../npcs/client/ProfileClientConfig.java | 41 +++++++++++++ .../controllers/PlayerQuestController.java | 16 +++++- .../npcs/controllers/ProfileConfigSync.java | 34 +++++++++++ .../noppes/npcs/controllers/data/Quest.java | 21 +++++-- 10 files changed, 179 insertions(+), 8 deletions(-) create mode 100644 src/main/java/kamkeel/npcs/network/packets/data/ProfileSharedQuestPacket.java create mode 100644 src/main/java/noppes/npcs/client/ProfileClientConfig.java create mode 100644 src/main/java/noppes/npcs/controllers/ProfileConfigSync.java diff --git a/src/main/java/kamkeel/npcs/controllers/ProfileController.java b/src/main/java/kamkeel/npcs/controllers/ProfileController.java index fcb3436af..c4be7322e 100644 --- a/src/main/java/kamkeel/npcs/controllers/ProfileController.java +++ b/src/main/java/kamkeel/npcs/controllers/ProfileController.java @@ -7,7 +7,9 @@ import kamkeel.npcs.controllers.data.profile.Profile; import kamkeel.npcs.controllers.data.profile.ProfileInfoEntry; import kamkeel.npcs.controllers.data.profile.ProfileOperation; import kamkeel.npcs.controllers.data.profile.Slot; +import kamkeel.npcs.network.packets.data.ProfileSharedQuestPacket; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import noppes.npcs.CustomNpcs; @@ -453,6 +455,9 @@ public class ProfileController implements IProfileHandler { PlayerDataScript handler = ScriptController.Instance.getPlayerScripts(profile.player); verifySlotQuests(profile.player); save(profile.player, profile); + if (profile.player instanceof EntityPlayerMP) { + ProfileSharedQuestPacket.sendToPlayer((EntityPlayerMP) profile.player); + } IPlayer scriptPlayer = (IPlayer) NpcAPI.Instance().getIEntity(profile.player); EventHooks.onProfileCreate(handler, scriptPlayer, profile, newSlotId, true); @@ -524,6 +529,9 @@ public class ProfileController implements IProfileHandler { saveSlotData(profile.player, profile, prevSlot); loadSlotData(profile.player, profile, newSlotId); syncSharedQuestsToPlayer(profile.player); + if (profile.player instanceof EntityPlayerMP) { + ProfileSharedQuestPacket.sendToPlayer((EntityPlayerMP) profile.player); + } EventHooks.onProfileChange(handler, scriptPlayer, profile, newSlotId, prevSlot, true); } else { @@ -901,5 +909,8 @@ public class ProfileController implements IProfileHandler { profile.sharedQuestTimestamps.put(questId, completeTime); } save(player, profile); + if (player instanceof EntityPlayerMP) { + ProfileSharedQuestPacket.sendToPlayer((EntityPlayerMP) player); + } } } diff --git a/src/main/java/kamkeel/npcs/controllers/SyncController.java b/src/main/java/kamkeel/npcs/controllers/SyncController.java index d0ee7b16c..57b111404 100644 --- a/src/main/java/kamkeel/npcs/controllers/SyncController.java +++ b/src/main/java/kamkeel/npcs/controllers/SyncController.java @@ -12,6 +12,7 @@ import kamkeel.npcs.network.PacketHandler; import kamkeel.npcs.network.enums.EnumSyncAction; import kamkeel.npcs.network.enums.EnumSyncType; import kamkeel.npcs.network.packets.data.LoginPacket; +import kamkeel.npcs.network.packets.data.ProfileSharedQuestPacket; import kamkeel.npcs.network.packets.data.ability.AbilityCooldownSyncPacket; import kamkeel.npcs.network.packets.data.ability.AbilityHotbarSyncPacket; import kamkeel.npcs.network.packets.data.ability.PlayerAbilitySyncPacket; @@ -184,6 +185,7 @@ public class SyncController { DBCAddon.instance.syncPlayer(player); syncPlayerData(player, false); PartyInfoPacket.sendPartyData(player); + ProfileSharedQuestPacket.sendToPlayer(player); // Sync skin overlays after full handshake to ensure the client is ready. // Overlays are not part of getSyncNBTFull(), and packets sent during diff --git a/src/main/java/kamkeel/npcs/network/PacketHandler.java b/src/main/java/kamkeel/npcs/network/PacketHandler.java index ef71ba967..06bffe6a7 100644 --- a/src/main/java/kamkeel/npcs/network/PacketHandler.java +++ b/src/main/java/kamkeel/npcs/network/PacketHandler.java @@ -586,6 +586,7 @@ public class PacketHandler { DATA_PACKET.registerPacket(new UpdateAnimationsPacket()); DATA_PACKET.registerPacket(new VillagerListPacket()); DATA_PACKET.registerPacket(new PlayerDataInfoPacket()); + DATA_PACKET.registerPacket(new ProfileSharedQuestPacket()); // Data | GUI Packets DATA_PACKET.registerPacket(new GuiClosePacket()); diff --git a/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java b/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java index 1a24ac2ef..598126a2d 100644 --- a/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java +++ b/src/main/java/kamkeel/npcs/network/enums/EnumDataPacket.java @@ -67,6 +67,9 @@ public enum EnumDataPacket { ABILITY_HOTBAR_SYNC, ABILITY_COOLDOWN_SYNC, + // Profile System + PROFILE_SHARED_QUEST, + // Auction System AUCTION_DATA, diff --git a/src/main/java/kamkeel/npcs/network/packets/data/ProfileSharedQuestPacket.java b/src/main/java/kamkeel/npcs/network/packets/data/ProfileSharedQuestPacket.java new file mode 100644 index 000000000..6fa6187c9 --- /dev/null +++ b/src/main/java/kamkeel/npcs/network/packets/data/ProfileSharedQuestPacket.java @@ -0,0 +1,57 @@ +package kamkeel.npcs.network.packets.data; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import io.netty.buffer.ByteBuf; +import kamkeel.npcs.network.AbstractPacket; +import kamkeel.npcs.network.PacketChannel; +import kamkeel.npcs.network.PacketHandler; +import kamkeel.npcs.network.enums.EnumDataPacket; +import kamkeel.npcs.util.ByteBufUtils; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.client.ProfileClientConfig; +import noppes.npcs.controllers.ProfileConfigSync; + +import java.io.IOException; + +public final class ProfileSharedQuestPacket extends AbstractPacket { + public static final String packetName = "Data|ProfileSharedQuest"; + + private NBTTagCompound compound; + + public ProfileSharedQuestPacket() { + } + + public ProfileSharedQuestPacket(NBTTagCompound compound) { + this.compound = compound; + } + + @Override + public Enum getType() { + return EnumDataPacket.PROFILE_SHARED_QUEST; + } + + @Override + public PacketChannel getChannel() { + return PacketHandler.DATA_PACKET; + } + + @Override + public void sendData(ByteBuf out) throws IOException { + ByteBufUtils.writeNBT(out, this.compound); + } + + @SideOnly(Side.CLIENT) + @Override + public void receiveData(ByteBuf in, EntityPlayer player) throws IOException { + NBTTagCompound nbt = ByteBufUtils.readNBT(in); + ProfileClientConfig.readFromNBT(nbt); + } + + public static void sendToPlayer(EntityPlayerMP player) { + NBTTagCompound compound = ProfileConfigSync.writeToNBT(player); + PacketHandler.Instance.sendToPlayer(new ProfileSharedQuestPacket(compound), player); + } +} diff --git a/src/main/java/noppes/npcs/client/ClientCacheHandler.java b/src/main/java/noppes/npcs/client/ClientCacheHandler.java index 30b14be83..3386ffb43 100644 --- a/src/main/java/noppes/npcs/client/ClientCacheHandler.java +++ b/src/main/java/noppes/npcs/client/ClientCacheHandler.java @@ -124,6 +124,7 @@ public class ClientCacheHandler { ClientCacheHandler.customOverlays.clear(); ClientCacheHandler.skinOverlays.clear(); ClientCacheHandler.playerAnimations.clear(); + ProfileClientConfig.reset(); // Clear Texture Caches GuiSoundSelection.cachedDomains.clear(); diff --git a/src/main/java/noppes/npcs/client/ProfileClientConfig.java b/src/main/java/noppes/npcs/client/ProfileClientConfig.java new file mode 100644 index 000000000..66c85a3d7 --- /dev/null +++ b/src/main/java/noppes/npcs/client/ProfileClientConfig.java @@ -0,0 +1,41 @@ +package noppes.npcs.client; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import java.util.HashMap; +import java.util.Map; + +public class ProfileClientConfig { + private static volatile Map sharedQuestTimestamps = new HashMap<>(); + + public static void readFromNBT(NBTTagCompound compound) { + if (compound == null) return; + + Map timestamps = new HashMap<>(); + if (compound.hasKey("SharedQuestTimestamps")) { + NBTTagList list = compound.getTagList("SharedQuestTimestamps", 10); + for (int i = 0; i < list.tagCount(); i++) { + NBTTagCompound entry = list.getCompoundTagAt(i); + timestamps.put(entry.getInteger("Quest"), entry.getLong("Date")); + } + } + sharedQuestTimestamps = timestamps; + } + + public static void reset() { + sharedQuestTimestamps = new HashMap<>(); + } + + public static Map getSharedQuestTimestamps() { + return sharedQuestTimestamps; + } + + public static boolean hasSharedQuest(int questId) { + return sharedQuestTimestamps.containsKey(questId); + } + + public static Long getSharedQuestTimestamp(int questId) { + return sharedQuestTimestamps.get(questId); + } +} diff --git a/src/main/java/noppes/npcs/controllers/PlayerQuestController.java b/src/main/java/noppes/npcs/controllers/PlayerQuestController.java index 288c24f79..a02808c33 100644 --- a/src/main/java/noppes/npcs/controllers/PlayerQuestController.java +++ b/src/main/java/noppes/npcs/controllers/PlayerQuestController.java @@ -2,6 +2,8 @@ package noppes.npcs.controllers; import kamkeel.npcs.controllers.ProfileController; import kamkeel.npcs.controllers.data.profile.Profile; +import noppes.npcs.client.ClientCacheHandler; +import noppes.npcs.client.ProfileClientConfig; import kamkeel.npcs.network.packets.data.AchievementPacket; import kamkeel.npcs.network.packets.data.ChatAlertPacket; import net.minecraft.entity.player.EntityPlayer; @@ -131,9 +133,17 @@ public class PlayerQuestController { boolean finishedLocally = data.finishedQuests.containsKey(quest.id); boolean completedShared = false; boolean hasCooldownShared = false; - if (ConfigMain.ProfilesEnabled && quest.profileOptions.enableOptions) { - Profile profile = ProfileController.Instance.getProfile(player); - if (profile != null && profile.sharedQuestTimestamps.containsKey(quest.id)) { + if (quest.profileOptions.enableOptions) { + boolean hasSharedTimestamp = false; + if (ProfileController.Instance != null) { + if (ConfigMain.ProfilesEnabled) { + Profile profile = ProfileController.Instance.getProfile(player); + hasSharedTimestamp = profile != null && profile.sharedQuestTimestamps.containsKey(quest.id); + } + } else if (ClientCacheHandler.allowProfiles) { + hasSharedTimestamp = ProfileClientConfig.hasSharedQuest(quest.id); + } + if (hasSharedTimestamp) { if (quest.profileOptions.completeControl == EnumProfileSync.Shared) completedShared = true; if (quest.profileOptions.cooldownControl == EnumProfileSync.Shared) diff --git a/src/main/java/noppes/npcs/controllers/ProfileConfigSync.java b/src/main/java/noppes/npcs/controllers/ProfileConfigSync.java new file mode 100644 index 000000000..5291ff1fd --- /dev/null +++ b/src/main/java/noppes/npcs/controllers/ProfileConfigSync.java @@ -0,0 +1,34 @@ +package noppes.npcs.controllers; + +import kamkeel.npcs.controllers.ProfileController; +import kamkeel.npcs.controllers.data.profile.Profile; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import noppes.npcs.config.ConfigMain; + +import java.util.Map; + +public class ProfileConfigSync { + public static NBTTagCompound writeToNBT(EntityPlayer player) { + NBTTagCompound compound = new NBTTagCompound(); + if (!ConfigMain.ProfilesEnabled || ProfileController.Instance == null) { + return compound; + } + + Profile profile = ProfileController.Instance.getProfile(player); + if (profile == null) { + return compound; + } + + NBTTagList questList = new NBTTagList(); + for (Map.Entry entry : profile.sharedQuestTimestamps.entrySet()) { + NBTTagCompound questEntry = new NBTTagCompound(); + questEntry.setInteger("Quest", entry.getKey()); + questEntry.setLong("Date", entry.getValue()); + questList.appendTag(questEntry); + } + compound.setTag("SharedQuestTimestamps", questList); + return compound; + } +} diff --git a/src/main/java/noppes/npcs/controllers/data/Quest.java b/src/main/java/noppes/npcs/controllers/data/Quest.java index c2b9ac397..a547743e4 100644 --- a/src/main/java/noppes/npcs/controllers/data/Quest.java +++ b/src/main/java/noppes/npcs/controllers/data/Quest.java @@ -2,6 +2,8 @@ package noppes.npcs.controllers.data; import kamkeel.npcs.controllers.ProfileController; import kamkeel.npcs.controllers.data.profile.Profile; +import noppes.npcs.client.ClientCacheHandler; +import noppes.npcs.client.ProfileClientConfig; import kamkeel.npcs.network.packets.data.QuestCompletionPacket; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; @@ -176,13 +178,22 @@ public class Quest implements ICompatibilty, IQuest { } public long getTimeUntilRepeat(EntityPlayer player) { - if (ConfigMain.ProfilesEnabled && profileOptions.enableOptions && profileOptions.cooldownControl == EnumProfileSync.Shared) { - Profile profile = ProfileController.Instance.getProfile(player); - if (profile != null) { - Long questTime = profile.sharedQuestTimestamps.get(this.id); - if (questTime == null) return 0L; + if (profileOptions.enableOptions && profileOptions.cooldownControl == EnumProfileSync.Shared) { + Long questTime = null; + if (ProfileController.Instance != null) { + if (ConfigMain.ProfilesEnabled) { + Profile profile = ProfileController.Instance.getProfile(player); + if (profile != null) { + questTime = profile.sharedQuestTimestamps.get(this.id); + } + } + } else if (ClientCacheHandler.allowProfiles) { + questTime = ProfileClientConfig.getSharedQuestTimestamp(this.id); + } + if (questTime != null) { return calculateRemainingCooldown(player, questTime); } + return 0L; } IPlayerQuestData questData = PlayerData.get(player).getQuestData(); return getTimeUntilRepeatQuestData(player, questData);