package mhfc.net.common.core.registry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import mhfc.net.MHFCMain;
import mhfc.net.common.core.data.KeyToInstanceRegistryData;
import mhfc.net.common.network.PacketPipeline;
import mhfc.net.common.network.message.quest.MessageMHFCInteraction;
import mhfc.net.common.network.message.quest.MessageMissionStatus;
import mhfc.net.common.network.message.quest.MessageMissionUpdate;
import mhfc.net.common.network.message.quest.MessageQuestRunningSubscription;
import mhfc.net.common.network.message.quest.MessageRequestMissionUpdate;
import mhfc.net.common.quests.Mission;
import mhfc.net.common.quests.QuestFactories;
import mhfc.net.common.quests.api.QuestDefinition;
import mhfc.net.common.util.services.IServiceKey;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.ChatComponentText;
public class MHFCQuestRegistry {
public static void staticInit() {}
private static final IServiceKey<MHFCQuestRegistry> serviceAccess = RegistryWrapper.registerService(
"quest manager",
MHFCQuestRegistry::new,
MHFCQuestRegistry::shutdown,
MHFCMain.serverRunningPhase);
public static class RegistryRequestVisualHandler
implements
IMessageHandler<MessageRequestMissionUpdate, MessageMissionUpdate> {
@Override
public MessageMissionUpdate onMessage(MessageRequestMissionUpdate message, MessageContext ctx) {
String identifier = message.getIdentifier();
Mission runningQuest = getRegistry().getRunningQuest(identifier);
if (runningQuest == null) {
return null;
}
return runningQuest.createFullUpdateMessage();
}
}
public static class RunningSubscriptionHandler
implements
IMessageHandler<MessageQuestRunningSubscription, IMessage> {
private static Set<EntityPlayerMP> subscribers = new HashSet<>();
public RunningSubscriptionHandler() {}
@Override
public IMessage onMessage(MessageQuestRunningSubscription message, MessageContext ctx) {
EntityPlayerMP player = ctx.getServerHandler().playerEntity;
if (message.isSubscribed()) {
boolean newSubscription = subscribers.add(player);
if (newSubscription) {
sendAllTo(player);
}
} else {
subscribers.remove(player);
}
return null;
}
public static void sendAllTo(EntityPlayerMP player) {
for (Mission q : getRegistry().questsRunning) {
MessageMissionUpdate missionUpdate = q.createFullUpdateMessage();
PacketPipeline.networkPipe.sendTo(missionUpdate, player);
}
}
public static void sendToAll(IMessage message) {
Iterator<EntityPlayerMP> iter = subscribers.iterator();
while (iter.hasNext()) {
PacketPipeline.networkPipe.sendTo(message, iter.next());
}
}
}
public static class QuestEventHandler {
@SubscribeEvent
public void onPlayerJoin(PlayerLoggedInEvent logIn) {
EntityPlayerMP player = EntityPlayerMP.class.cast(logIn.player);
RunningSubscriptionHandler.subscribers.add(player);
for (Entry<String, Mission> mission : getRegistry().runningQuestRegistry.getFrozenDataMap().entrySet()) {
String missionID = mission.getKey();
String questID = getRegistry().missionIDtoQuestID.get(missionID);
PacketPipeline.networkPipe.sendTo(MessageMissionStatus.creation(questID, missionID), player);
}
}
@SubscribeEvent
public void onPlayerLeave(PlayerLoggedOutEvent logOut) {
EntityPlayerMP player = EntityPlayerMP.class.cast(logOut.player);
Mission quest = getRegistry().getQuestForPlayer(player);
if (quest == null) {
return;
}
quest.quitPlayer(player);
RunningSubscriptionHandler.subscribers.remove(player);
}
@SubscribeEvent
public void onServerTick(TickEvent.ServerTickEvent ticking) {
if (ticking.phase != Phase.START) {
return;
}
for (Mission mission : getRegistry().questsRunning) {
mission.updateCheck();
}
}
}
private static int questIDCounter = 0;
public void onPlayerInteraction(EntityPlayerMP player, MessageMHFCInteraction message) {
switch (message.getInteraction()) {
case NEW_QUEST:
createNewQuest(player, message);
return;
case ACCEPT_QUEST:
acceptQuest(player, message);
break;
case START_QUEST:
voteStartQuest(player);
break;
case END_QUEST:
voteEndQuest(player);
break;
case FORFEIT_QUEST:
forfeitQuest(player);
break;
case MOD_RELOAD:
for (Mission genQ : questsRunning) {
RunningSubscriptionHandler.sendToAll(genQ.createFullUpdateMessage());
}
break;
default:
break;
}
}
private void forfeitQuest(EntityPlayerMP player) {
Mission quest = getQuestForPlayer(player);
if (quest != null) {
quest.quitPlayer(player);
player.addChatMessage(new ChatComponentText("You have forfeited a quest"));
} else {
sendResetPlayerVisual(player);
}
}
private void voteEndQuest(EntityPlayerMP player) {
Mission quest = getQuestForPlayer(player);
if (quest != null) {
quest.voteEnd(player);
player.addChatMessage(new ChatComponentText("You have voted for ending the quest"));
} else {
sendResetPlayerVisual(player);
}
}
private void voteStartQuest(EntityPlayerMP player) {
Mission quest = getQuestForPlayer(player);
if (quest != null) {
quest.voteStart(player);
player.addChatMessage(new ChatComponentText("You have voted for starting the quest"));
}
}
private void acceptQuest(EntityPlayerMP player, MessageMHFCInteraction message) {
Mission quest = getRunningQuest(message.getOptions()[0]);
if (quest != null) {
quest.joinPlayer(player);
player.addChatMessage(new ChatComponentText("You have accepted a quest"));
} else {
player.addChatMessage(new ChatComponentText("The quest you wanted to accept does not exist"));
}
}
private void createNewQuest(EntityPlayerMP player, MessageMHFCInteraction message) {
Mission quest = getQuestForPlayer(player);
if (quest != null) {
player.addChatMessage(new ChatComponentText("You already are on quest " + getIdentifierForQuest(quest)));
PacketPipeline.networkPipe.sendTo(quest.createFullUpdateMessage(), player);
return;
}
String questID = message.getOptions()[0];
QuestDefinition questDescription = MHFCQuestBuildRegistry.getQuestDescription(questID);
if (questDescription == null) {
player.addChatMessage(new ChatComponentText("Quest with id[" + questID + "] not found"));
return;
}
String missionID = questID + "@" + player.getDisplayName() + "@" + questIDCounter++;
Mission newQuest = QuestFactories.constructQuest(questDescription, missionID);
if (newQuest == null) {
player.addChatMessage(new ChatComponentText("Quest with id[" + questID + "] could not be constructed"));
return;
}
if (!newQuest.canJoin(player)) {
newQuest.close();
return;
}
startMission(questID, newQuest, missionID);
newQuest.joinPlayer(player);
}
private void sendResetPlayerVisual(EntityPlayerMP player) {
String missionID = getMissionIDForPlayer(player);
if (missionID == null) {
return;
}
PacketPipeline.networkPipe.sendTo(MessageMissionStatus.departing(missionID), player);
}
protected Map<EntityPlayer, String> playerQuest = new HashMap<>();
protected List<Mission> questsRunning = new ArrayList<>();
protected KeyToInstanceRegistryData<String, Mission> runningQuestRegistry = new KeyToInstanceRegistryData<>();
protected Map<String, String> missionIDtoQuestID = new HashMap<>();
private QuestEventHandler connectionHandler;
private MHFCQuestRegistry() {
FMLCommonHandler.instance().bus().register(connectionHandler = new QuestEventHandler());
}
private void shutdown() {
FMLCommonHandler.instance().bus().unregister(connectionHandler);
}
public Mission getRunningQuest(String string) {
return runningQuestRegistry.getData(string);
}
/**
* Get the quest on which a player is on. If the player is on no quest then null is returned.
*/
public Mission getQuestForPlayer(EntityPlayer player) {
return runningQuestRegistry.getData(playerQuest.get(player));
}
/**
* Get the id of the mission the player is on. If the player is not currently on a mission, null is returned.
*
* @param player
* @return
*/
public String getMissionIDForPlayer(EntityPlayer player) {
return playerQuest.get(player);
}
/**
* Returns all quests that are running at the moment.
*/
public List<Mission> getRunningQuests() {
return questsRunning;
}
/**
* Returns the identifier for a quest
*/
public String getIdentifierForQuest(Mission quest) {
return runningQuestRegistry.getKey(quest);
}
/**
* Sets the quest for a player, use null to remove the entry
*
*/
public void setQuestForPlayer(EntityPlayer player, Mission generalQuest) {
if (generalQuest == null) {
playerQuest.remove(player);
} else {
playerQuest.put(player, runningQuestRegistry.getKey(generalQuest));
}
}
/**
* Should be called when a new quest was started
*/
private boolean startMission(String questID, Mission mission, String missionID) {
if (!runningQuestRegistry.offerMapping(missionID, mission)) {
return false;
}
questsRunning.add(mission);
missionIDtoQuestID.put(missionID, questID);
MessageMissionStatus message = MessageMissionStatus.creation(questID, missionID);
RunningSubscriptionHandler.sendToAll(message);
return true;
}
/**
* Should be called when a quest is no longer running and was terminated. Might also be called to ensure client
* sync. Returns true if the quest was registered.
*/
public boolean endMission(Mission mission) {
boolean wasRunning = questsRunning.remove(mission);
if (wasRunning) {
String missionID = runningQuestRegistry.removeKey(mission);
missionIDtoQuestID.remove(missionID);
MessageMissionStatus message = MessageMissionStatus.destruction(missionID);
RunningSubscriptionHandler.sendToAll(message);
}
mission.close();
return wasRunning;
}
/**
* Should be called when major changes to a quest were made that require resending the information to all clients
*/
public void questUpdated(Mission quest) {
String missionID = runningQuestRegistry.getKey(quest);
if (quest == null || missionID == null) {
return;
}
MessageMissionUpdate message = quest.createFullUpdateMessage();
RunningSubscriptionHandler.sendToAll(message);
}
public static MHFCQuestRegistry getRegistry() {
return serviceAccess.getService();
}
}