mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-08 11:24:11 +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);
|
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
|
* Sends this sender a message raw
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package org.bukkit.conversations;
|
package org.bukkit.conversations;
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -37,6 +36,7 @@ public class Conversation {
|
||||||
protected boolean localEchoEnabled;
|
protected boolean localEchoEnabled;
|
||||||
protected ConversationPrefix prefix;
|
protected ConversationPrefix prefix;
|
||||||
protected List<ConversationCanceller> cancellers;
|
protected List<ConversationCanceller> cancellers;
|
||||||
|
protected List<ConversationAbandonedListener> abandonedListeners;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new Conversation.
|
* Initializes a new Conversation.
|
||||||
|
@ -62,6 +62,7 @@ public class Conversation {
|
||||||
this.localEchoEnabled = true;
|
this.localEchoEnabled = true;
|
||||||
this.prefix = new NullConversationPrefix();
|
this.prefix = new NullConversationPrefix();
|
||||||
this.cancellers = new ArrayList<ConversationCanceller>();
|
this.cancellers = new ArrayList<ConversationCanceller>();
|
||||||
|
this.abandonedListeners = new ArrayList<ConversationAbandonedListener>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -190,7 +191,7 @@ public class Conversation {
|
||||||
// Test for conversation abandonment based on input
|
// Test for conversation abandonment based on input
|
||||||
for(ConversationCanceller canceller : cancellers) {
|
for(ConversationCanceller canceller : cancellers) {
|
||||||
if (canceller.cancelBasedOnInput(context, input)) {
|
if (canceller.cancelBasedOnInput(context, input)) {
|
||||||
abandon();
|
abandon(new ConversationAbandonedEvent(this, canceller));
|
||||||
return;
|
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.
|
* Abandons and resets the current conversation. Restores the user's normal chat behavior.
|
||||||
*/
|
*/
|
||||||
public void abandon() {
|
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) {
|
if (!abandoned) {
|
||||||
abandoned = true;
|
abandoned = true;
|
||||||
currentPrompt = null;
|
currentPrompt = null;
|
||||||
context.getForWhom().abandonConversation(this);
|
context.getForWhom().abandonConversation(this);
|
||||||
|
for (ConversationAbandonedListener listener : abandonedListeners) {
|
||||||
|
listener.conversationAbandoned(details);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +245,7 @@ public class Conversation {
|
||||||
*/
|
*/
|
||||||
public void outputNextPrompt() {
|
public void outputNextPrompt() {
|
||||||
if (currentPrompt == null) {
|
if (currentPrompt == null) {
|
||||||
abandon();
|
abandon(new ConversationAbandonedEvent(this));
|
||||||
} else {
|
} else {
|
||||||
context.getForWhom().sendRawMessage(prefix.getPrefix(context) + currentPrompt.getPromptText(context));
|
context.getForWhom().sendRawMessage(prefix.getPrefix(context) + currentPrompt.getPromptText(context));
|
||||||
if (!currentPrompt.blocksForInput(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 Map<Object, Object> initialSessionData;
|
||||||
protected String playerOnlyMessage;
|
protected String playerOnlyMessage;
|
||||||
protected List<ConversationCanceller> cancellers;
|
protected List<ConversationCanceller> cancellers;
|
||||||
|
protected List<ConversationAbandonedListener> abandonedListeners;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a ConversationFactory.
|
* Constructs a ConversationFactory.
|
||||||
|
@ -39,6 +40,7 @@ public class ConversationFactory {
|
||||||
initialSessionData = new HashMap<Object, Object>();
|
initialSessionData = new HashMap<Object, Object>();
|
||||||
playerOnlyMessage = null;
|
playerOnlyMessage = null;
|
||||||
cancellers = new ArrayList<ConversationCanceller>();
|
cancellers = new ArrayList<ConversationCanceller>();
|
||||||
|
abandonedListeners = new ArrayList<ConversationAbandonedListener>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -141,6 +143,16 @@ public class ConversationFactory {
|
||||||
return this;
|
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.
|
* Constructs a {@link Conversation} in accordance with the defaults set for this factory.
|
||||||
* @param forWhom The entity for whom the new conversation is mediating.
|
* @param forWhom The entity for whom the new conversation is mediating.
|
||||||
|
@ -167,6 +179,11 @@ public class ConversationFactory {
|
||||||
conversation.addConversationCanceller(canceller.clone());
|
conversation.addConversationCanceller(canceller.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Add the ConversationAbandonedListeners
|
||||||
|
for (ConversationAbandonedListener listener : abandonedListeners) {
|
||||||
|
conversation.addConversationAbandonedListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
return conversation;
|
return conversation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class InactivityConversationCanceller implements ConversationCanceller {
|
||||||
startTimer();
|
startTimer();
|
||||||
} else if (conversation.getState() == Conversation.ConversationState.STARTED) {
|
} else if (conversation.getState() == Conversation.ConversationState.STARTED) {
|
||||||
cancelling(conversation);
|
cancelling(conversation);
|
||||||
conversation.abandon();
|
conversation.abandon(new ConversationAbandonedEvent(conversation, InactivityConversationCanceller.this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, timeoutSeconds * 20);
|
}, 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 String lastSentMessage;
|
||||||
public Conversation begunConversation;
|
public Conversation begunConversation;
|
||||||
public Conversation abandonedConverstion;
|
public Conversation abandonedConverstion;
|
||||||
|
public ConversationAbandonedEvent abandonedConversationEvent;
|
||||||
|
|
||||||
public boolean isConversing() {
|
public boolean isConversing() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -33,6 +34,11 @@ public class FakeConversable implements Conversable {
|
||||||
abandonedConverstion = conversation;
|
abandonedConverstion = conversation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
|
||||||
|
abandonedConverstion = conversation;
|
||||||
|
abandonedConversationEvent = details;
|
||||||
|
}
|
||||||
|
|
||||||
public void sendRawMessage(String message) {
|
public void sendRawMessage(String message) {
|
||||||
lastSentMessage = message;
|
lastSentMessage = message;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.util.UUID;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.conversations.Conversation;
|
import org.bukkit.conversations.Conversation;
|
||||||
|
import org.bukkit.conversations.ConversationAbandonedEvent;
|
||||||
import org.bukkit.entity.Arrow;
|
import org.bukkit.entity.Arrow;
|
||||||
import org.bukkit.entity.Egg;
|
import org.bukkit.entity.Egg;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
|
@ -739,4 +740,8 @@ public class TestPlayer implements Player {
|
||||||
public void abandonConversation(Conversation conversation) {
|
public void abandonConversation(Conversation conversation) {
|
||||||
throw new UnsupportedOperationException("Not supported yet.");
|
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