mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-05 18:27:17 +01:00
[Bleeding] Added ConversationAbandonedEvent and supporting infrastructure. Whenever a conversation exits, the ConversationAbandonedEvent is triggered with details about how the conversation ended and what, if anything caused it to end. Fixes BUKKIT-986
By: rmichela <deltahat@gmail.com>
This commit is contained in:
parent
819611b351
commit
4b5a0b8ed8
9 changed files with 149 additions and 6 deletions
|
@ -33,6 +33,13 @@ public interface Conversable {
|
|||
*/
|
||||
public void abandonConversation(Conversation conversation);
|
||||
|
||||
/**
|
||||
* Abandons an active conversation.
|
||||
* @param conversation The conversation to abandon
|
||||
* @param details Details about why the conversation was abandoned
|
||||
*/
|
||||
public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details);
|
||||
|
||||
/**
|
||||
* Sends this sender a message raw
|
||||
*
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.bukkit.conversations;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -37,6 +36,7 @@ public class Conversation {
|
|||
protected boolean localEchoEnabled;
|
||||
protected ConversationPrefix prefix;
|
||||
protected List<ConversationCanceller> cancellers;
|
||||
protected List<ConversationAbandonedListener> abandonedListeners;
|
||||
|
||||
/**
|
||||
* Initializes a new Conversation.
|
||||
|
@ -62,6 +62,7 @@ public class Conversation {
|
|||
this.localEchoEnabled = true;
|
||||
this.prefix = new NullConversationPrefix();
|
||||
this.cancellers = new ArrayList<ConversationCanceller>();
|
||||
this.abandonedListeners = new ArrayList<ConversationAbandonedListener>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -190,7 +191,7 @@ public class Conversation {
|
|||
// Test for conversation abandonment based on input
|
||||
for(ConversationCanceller canceller : cancellers) {
|
||||
if (canceller.cancelBasedOnInput(context, input)) {
|
||||
abandon();
|
||||
abandon(new ConversationAbandonedEvent(this, canceller));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -201,14 +202,41 @@ public class Conversation {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link ConversationAbandonedListener}.
|
||||
* @param listener The listener to add.
|
||||
*/
|
||||
public synchronized void addConversationAbandonedListener(ConversationAbandonedListener listener) {
|
||||
abandonedListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a {@link ConversationAbandonedListener}.
|
||||
* @param listener The listener to remove.
|
||||
*/
|
||||
public synchronized void removeConversationAbandonedListener(ConversationAbandonedListener listener) {
|
||||
abandonedListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Abandons and resets the current conversation. Restores the user's normal chat behavior.
|
||||
*/
|
||||
public void abandon() {
|
||||
abandon(new ConversationAbandonedEvent(this, new ManuallyAbandonedConversationCanceller()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Abandons and resets the current conversation. Restores the user's normal chat behavior.
|
||||
* @param details Details about why the conversation was abandoned
|
||||
*/
|
||||
public synchronized void abandon(ConversationAbandonedEvent details) {
|
||||
if (!abandoned) {
|
||||
abandoned = true;
|
||||
currentPrompt = null;
|
||||
context.getForWhom().abandonConversation(this);
|
||||
for (ConversationAbandonedListener listener : abandonedListeners) {
|
||||
listener.conversationAbandoned(details);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,7 +245,7 @@ public class Conversation {
|
|||
*/
|
||||
public void outputNextPrompt() {
|
||||
if (currentPrompt == null) {
|
||||
abandon();
|
||||
abandon(new ConversationAbandonedEvent(this));
|
||||
} else {
|
||||
context.getForWhom().sendRawMessage(prefix.getPrefix(context) + currentPrompt.getPromptText(context));
|
||||
if (!currentPrompt.blocksForInput(context)) {
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package org.bukkit.conversations;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* ConversationAbandonedEvent contains information about an abandoned conversation.
|
||||
*/
|
||||
public class ConversationAbandonedEvent extends EventObject {
|
||||
|
||||
private ConversationContext context;
|
||||
private ConversationCanceller canceller;
|
||||
|
||||
public ConversationAbandonedEvent(Conversation conversation) {
|
||||
this(conversation, null);
|
||||
}
|
||||
|
||||
public ConversationAbandonedEvent(Conversation conversation, ConversationCanceller canceller) {
|
||||
super(conversation);
|
||||
this.context = conversation.getContext();
|
||||
this.canceller = canceller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object that caused the conversation to be abandoned.
|
||||
* @return The object that abandoned the conversation.
|
||||
*/
|
||||
public ConversationCanceller getCanceller() {
|
||||
return canceller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the abandoned conversation's conversation context.
|
||||
* @return The abandoned conversation's conversation context.
|
||||
*/
|
||||
public ConversationContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates how the conversation was abandoned - naturally as part of the prompt chain or prematurely via a
|
||||
* {@link ConversationCanceller}.
|
||||
* @return True if the conversation is abandoned gracefully by a {@link Prompt} returning null
|
||||
* or the next prompt. False of the conversations is abandoned prematurely by a ConversationCanceller.
|
||||
*/
|
||||
public boolean gracefulExit() {
|
||||
return canceller == null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package org.bukkit.conversations;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
*/
|
||||
public interface ConversationAbandonedListener extends EventListener {
|
||||
/**
|
||||
* Called whenever a {@link Conversation} is abandoned.
|
||||
* @param abandonedEvent Contains details about the abandoned conversation.
|
||||
*/
|
||||
public void conversationAbandoned(ConversationAbandonedEvent abandonedEvent);
|
||||
}
|
|
@ -25,6 +25,7 @@ public class ConversationFactory {
|
|||
protected Map<Object, Object> initialSessionData;
|
||||
protected String playerOnlyMessage;
|
||||
protected List<ConversationCanceller> cancellers;
|
||||
protected List<ConversationAbandonedListener> abandonedListeners;
|
||||
|
||||
/**
|
||||
* Constructs a ConversationFactory.
|
||||
|
@ -39,6 +40,7 @@ public class ConversationFactory {
|
|||
initialSessionData = new HashMap<Object, Object>();
|
||||
playerOnlyMessage = null;
|
||||
cancellers = new ArrayList<ConversationCanceller>();
|
||||
abandonedListeners = new ArrayList<ConversationAbandonedListener>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,6 +143,16 @@ public class ConversationFactory {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link ConversationAbandonedListener} to all conversations constructed by this factory.
|
||||
* @param listener The listener to add.
|
||||
* @return This object.
|
||||
*/
|
||||
public ConversationFactory addConversationAbandonedListener(ConversationAbandonedListener listener) {
|
||||
abandonedListeners.add(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link Conversation} in accordance with the defaults set for this factory.
|
||||
* @param forWhom The entity for whom the new conversation is mediating.
|
||||
|
@ -148,7 +160,7 @@ public class ConversationFactory {
|
|||
*/
|
||||
public Conversation buildConversation(Conversable forWhom) {
|
||||
//Abort conversation construction if we aren't supposed to talk to non-players
|
||||
if(playerOnlyMessage != null && !(forWhom instanceof Player)) {
|
||||
if (playerOnlyMessage != null && !(forWhom instanceof Player)) {
|
||||
return new Conversation(plugin, forWhom, new NotPlayerMessagePrompt());
|
||||
}
|
||||
|
||||
|
@ -163,9 +175,14 @@ public class ConversationFactory {
|
|||
conversation.setPrefix(prefix);
|
||||
|
||||
//Clone the conversation cancellers
|
||||
for(ConversationCanceller canceller : cancellers) {
|
||||
for (ConversationCanceller canceller : cancellers) {
|
||||
conversation.addConversationCanceller(canceller.clone());
|
||||
}
|
||||
|
||||
//Add the ConversationAbandonedListeners
|
||||
for (ConversationAbandonedListener listener : abandonedListeners) {
|
||||
conversation.addConversationAbandonedListener(listener);
|
||||
}
|
||||
|
||||
return conversation;
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public class InactivityConversationCanceller implements ConversationCanceller {
|
|||
startTimer();
|
||||
} else if (conversation.getState() == Conversation.ConversationState.STARTED) {
|
||||
cancelling(conversation);
|
||||
conversation.abandon();
|
||||
conversation.abandon(new ConversationAbandonedEvent(conversation, InactivityConversationCanceller.this));
|
||||
}
|
||||
}
|
||||
}, timeoutSeconds * 20);
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package org.bukkit.conversations;
|
||||
|
||||
/**
|
||||
* The ManuallyAbandonedConversationCanceller is only used as part of a {@link ConversationAbandonedEvent} to indicate
|
||||
* that the conversation was manually abandoned by programatically calling the abandon() method on it.
|
||||
*/
|
||||
public class ManuallyAbandonedConversationCanceller implements ConversationCanceller{
|
||||
public void setConversation(Conversation conversation) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean cancelBasedOnInput(ConversationContext context, String input) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ConversationCanceller clone() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ public class FakeConversable implements Conversable {
|
|||
public String lastSentMessage;
|
||||
public Conversation begunConversation;
|
||||
public Conversation abandonedConverstion;
|
||||
public ConversationAbandonedEvent abandonedConversationEvent;
|
||||
|
||||
public boolean isConversing() {
|
||||
return false;
|
||||
|
@ -33,6 +34,11 @@ public class FakeConversable implements Conversable {
|
|||
abandonedConverstion = conversation;
|
||||
}
|
||||
|
||||
public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
|
||||
abandonedConverstion = conversation;
|
||||
abandonedConversationEvent = details;
|
||||
}
|
||||
|
||||
public void sendRawMessage(String message) {
|
||||
lastSentMessage = message;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.UUID;
|
|||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.conversations.Conversation;
|
||||
import org.bukkit.conversations.ConversationAbandonedEvent;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.Egg;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
@ -739,4 +740,8 @@ public class TestPlayer implements Player {
|
|||
public void abandonConversation(Conversation conversation) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue