package joshie.harvest.quests.data;
import joshie.harvest.api.HFApi;
import joshie.harvest.api.calendar.CalendarDate;
import joshie.harvest.api.quests.Quest;
import joshie.harvest.api.quests.TargetType;
import joshie.harvest.core.HFTrackers;
import joshie.harvest.core.util.interfaces.ISyncMaster;
import joshie.harvest.quests.packet.PacketQuestCompleted;
import joshie.harvest.quests.packet.PacketQuestConnect;
import joshie.harvest.quests.packet.PacketQuestRemove;
import joshie.harvest.quests.packet.PacketQuestSetCurrent;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static joshie.harvest.core.helpers.SerializeHelper.readMap;
import static joshie.harvest.core.helpers.SerializeHelper.writeMap;
public class QuestDataServer extends QuestData {
private final ISyncMaster master;
private Map<Quest, CalendarDate> lastFinished = new HashMap<>();
public QuestDataServer(ISyncMaster master) {
this.master = master;
}
public void purge(EntityPlayerMP player) {
current.clear();
finished.clear();
lastFinished.clear();
sync(player); //Resync everything
}
public CalendarDate getLastCompletionOfQuest(Quest quest) {
return lastFinished.get(quest);
}
@Override
public boolean startQuest(Quest q, boolean sync, @Nullable NBTTagCompound tag) {
try {
if (!finished.contains(q) || q.isRepeatable()) {
Quest quest = q.getClass().newInstance().setRegistryName(q.getRegistryName()).setStage(0); //Set the current quest to your new
if (tag != null) { //Default information
quest.readFromNBT(tag);
}
quest.onQuestActivated();
current.add(quest);
if (sync ) {
master.sync(null, new PacketQuestSetCurrent(quest));
}
return true;
} else return false;
} catch (Exception ignored) { return false; }
}
private void finish(@Nonnull World world, @Nullable EntityPlayer player, Quest quest, boolean rewards) {
finished.add(quest);
if (rewards && player != null) {
quest.onQuestCompleted(player); //Complete the quest, then add any notes
quest.getNotes().stream().forEach(note -> HFApi.player.getTrackingForPlayer(player).learnNote(note));
}
if (quest.isRepeatable() && quest.getDaysBetween() > 0) {
lastFinished.put(quest, HFApi.calendar.getDate(world).copy());
}
}
//Quests should always REMOVE from the current quests, and add to the finished quests THEMSELVES
//Only the person who actually completed the quest, will get the reward
@Override
public void markCompleted(@Nonnull World world, @Nullable EntityPlayer player, Quest quest, boolean rewards) {
Quest localQuest = getAQuest(quest);
if (localQuest != null) {
current.remove(localQuest);
finish(world, player, localQuest, rewards);
} else finish(world, player, quest, rewards);
HFTrackers.markTownsDirty();
//Sync everything
if ((quest.getQuestType() == TargetType.PLAYER || (quest.getQuestType() == TargetType.TOWN && rewards))) master.sync(player, new PacketQuestCompleted(quest, rewards)); //Let this player claim the reward
else if (quest.getQuestType() == TargetType.TOWN) master.sync(null, new PacketQuestCompleted(quest, false)); //Let the rest of the server know this was completed
updateQuests(true); //Update the world on these quests, everytime one is completed
}
@Override
public void removeAsCurrent(@Nonnull World world, Quest quest) {
current.remove(quest);
finished.remove(quest);
HFTrackers.markTownsDirty();
if (quest.getQuestType() == TargetType.TOWN) master.sync(null, new PacketQuestRemove(quest)); //Let the rest of the server know this was completed
updateQuests(true); //Update the world on these quests, everytime one is completed
}
private void updateQuests(boolean sync) {
for (Quest quest : Quest.REGISTRY.getValues()) {
updateQuests(quest, sync);
}
}
public void sync(@Nullable EntityPlayerMP player) {
updateQuests(false); //Don't bother syncing as we're going to send it all at once!
master.sync(player, new PacketQuestConnect(writeToNBT(new NBTTagCompound())));
}
private void updateQuests(Quest quest, boolean sync) {
if (quest.getQuestType() != master.getTargetType()) return; //If we aren't the same quest type, we don't get counted
//Check if the quest can be complete
//If the quest isn't finished, do stuff
if (!finished.contains(quest) || quest.isRepeatable()) {
//If we aren't already working on this quest, and we can start it, then start the quest
if (!current.contains(quest) && canStart(quest, current, finished)) {
startQuest(quest, sync, null);
}
}
}
private boolean canStart(Quest quest, Set<Quest> active, Set<Quest> finished) {
return quest.canStartQuest(active, finished);
}
@Override
public void readFromNBT(NBTTagCompound nbt) {
super.readFromNBT(nbt);
lastFinished = readMap(Quest.class, CalendarDate.class, "LastQuest", nbt);
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
writeMap(lastFinished, "LastQuest", nbt);
return super.writeToNBT(nbt);
}
}