/**
  * Returns true if the given quest made progress and/or no further interactions should occur.
  *
  * @param player
  * @param quest Quest instance to check for progress
  * @param handler IQuestHandler will have its methods called at appropriate times; pass {@link
  *     #DEFAULT_QUEST_HANDLER} if none available
  * @param data Optional arguments passed to the various {@code IQuest} methods, e.g. {@link
  *     IQuest#begin begin} and {@link IQuest#complete complete}
  * @return True if something happened, i.e. the calling interaction should be canceled
  */
 public static boolean checkQuestProgress(
     EntityPlayer player, IQuest quest, IQuestHandler handler, Object... data) {
   boolean changed = false;
   if (quest.isComplete(player)) {
     // do nothing if quest is already complete
   } else if (quest.canBegin(player)) {
     if (quest.begin(player, data)) {
       handler.onQuestBegun(quest, player);
       changed = true;
     }
   } else if (quest.canComplete(player)) {
     if (quest.complete(player, data)) {
       handler.onQuestCompleted(quest, player);
       changed = true;
     }
   } else if (quest.hasBegun(player) && quest.update(player, data)) {
     handler.onQuestChanged(quest, player);
     changed = true;
   }
   if (!changed) { // check for hint
     IChatComponent hint = quest.getHint(player, data);
     if (hint != null) { // result may be different on client vs. server due to Random
       if (!player.worldObj.isRemote && !hint.getFormattedText().equals("")) {
         player.addChatMessage(hint);
       }
       return true;
     }
   }
   if (changed && quest.requiresSync() && player instanceof EntityPlayerMP) {
     PacketDispatcher.sendTo(new SyncQuestPacket(quest), (EntityPlayerMP) player);
   }
   return changed;
 }
 /**
  * Reconstructs the IQuest instance from the NBTTagCompound, assuming the fully qualified class
  * name is stored using the key "QuestClass"
  */
 public static IQuest loadFromNBT(NBTTagCompound compound) {
   try {
     Class<?> clazz = Class.forName(compound.getString("QuestClass"));
     Object o = clazz.newInstance();
     if (o instanceof IQuest) {
       ((IQuest) o).readFromNBT(compound);
       return (IQuest) o;
     } else {
       ZSSMain.logger.warn("Failed to load quest from NBT: " + compound);
     }
   } catch (ClassNotFoundException e) {
     e.printStackTrace();
   } catch (InstantiationException e) {
     e.printStackTrace();
   } catch (IllegalAccessException e) {
     e.printStackTrace();
   }
   return null;
 }
 /** Writes the quest to NBT, guaranteeing that the fully qualified class name is included */
 public static NBTTagCompound saveToNBT(IQuest quest) {
   NBTTagCompound compound = new NBTTagCompound();
   quest.writeToNBT(compound);
   compound.setString("QuestClass", quest.getClass().getName());
   return compound;
 }