mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
Give ChatBots access to plugin channels.
Chatbots may find it useful to send messages over plugin channels. This allows REGISTERing, UNREGISTERing, and sending over plugin channels, with built-in checking if the server also registered the channel (which can be disabled by the bot if needed). Unused channels are UNREGISTERed when a bot is disabled.
This commit is contained in:
parent
bdbd8ab0b8
commit
1ea8f119d9
5 changed files with 215 additions and 3 deletions
|
|
@ -41,6 +41,7 @@ namespace MinecraftClient
|
||||||
private McTcpClient Handler { get { return master != null ? master.Handler : _handler; } }
|
private McTcpClient Handler { get { return master != null ? master.Handler : _handler; } }
|
||||||
private McTcpClient _handler = null;
|
private McTcpClient _handler = null;
|
||||||
private ChatBot master = null;
|
private ChatBot master = null;
|
||||||
|
private List<string> registeredPluginChannels = new List<String>();
|
||||||
private Queue<string> chatQueue = new Queue<string>();
|
private Queue<string> chatQueue = new Queue<string>();
|
||||||
private DateTime? lastMessageSentTime = DateTime.MinValue;
|
private DateTime? lastMessageSentTime = DateTime.MinValue;
|
||||||
private bool CanSendTextNow
|
private bool CanSendTextNow
|
||||||
|
|
@ -100,6 +101,17 @@ namespace MinecraftClient
|
||||||
|
|
||||||
public virtual bool OnDisconnect(DisconnectReason reason, string message) { return false; }
|
public virtual bool OnDisconnect(DisconnectReason reason, string message) { return false; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a plugin channel message is received.
|
||||||
|
/// The given channel must have previously been registered with RegisterPluginChannel.
|
||||||
|
/// This can be used to communicate with server mods or plugins. See wiki.vg for more
|
||||||
|
/// information about plugin channels: http://wiki.vg/Plugin_channel
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The name of the channel</param>
|
||||||
|
/// <param name="data">The payload for the message</param>
|
||||||
|
|
||||||
|
public virtual void OnPluginMessage(string channel, byte[] data) { }
|
||||||
|
|
||||||
/* =================================================================== */
|
/* =================================================================== */
|
||||||
/* ToolBox - Methods below might be useful while creating your bot. */
|
/* ToolBox - Methods below might be useful while creating your bot. */
|
||||||
/* You should not need to interact with other classes of the program. */
|
/* You should not need to interact with other classes of the program. */
|
||||||
|
|
@ -596,5 +608,48 @@ namespace MinecraftClient
|
||||||
return new string[0];
|
return new string[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers the given plugin channel for use by this chatbot.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The name of the channel to register</param>
|
||||||
|
|
||||||
|
protected void RegisterPluginChannel(string channel)
|
||||||
|
{
|
||||||
|
this.registeredPluginChannels.Add(channel);
|
||||||
|
Handler.RegisterPluginChannel(channel, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unregisters the given plugin channel, meaning this chatbot can no longer use it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The name of the channel to unregister</param>
|
||||||
|
|
||||||
|
protected void UnregisterPluginChannel(string channel)
|
||||||
|
{
|
||||||
|
this.registeredPluginChannels.RemoveAll(chan => chan == channel);
|
||||||
|
Handler.UnregisterPluginChannel(channel, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends the given plugin channel message to the server, if the channel has been registered.
|
||||||
|
/// See http://wiki.vg/Plugin_channel for more information about plugin channels.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The channel to send the message on.</param>
|
||||||
|
/// <param name="data">The data to send.</param>
|
||||||
|
/// <param name="sendEvenIfNotRegistered">Should the message be sent even if it hasn't been registered by the server or this bot? (Some Minecraft channels aren't registered)</param>
|
||||||
|
/// <returns>Whether the message was successfully sent. False if there was a network error or if the channel wasn't registered.</returns>
|
||||||
|
|
||||||
|
protected bool SendPluginChannelMessage(string channel, byte[] data, bool sendEvenIfNotRegistered = false)
|
||||||
|
{
|
||||||
|
if (!sendEvenIfNotRegistered)
|
||||||
|
{
|
||||||
|
if (!this.registeredPluginChannels.Contains(channel))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Handler.SendPluginChannelMessage(channel, data, sendEvenIfNotRegistered);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,21 @@ namespace MinecraftClient
|
||||||
private readonly List<ChatBot> bots = new List<ChatBot>();
|
private readonly List<ChatBot> bots = new List<ChatBot>();
|
||||||
private static readonly List<ChatBots.Script> scripts_on_hold = new List<ChatBots.Script>();
|
private static readonly List<ChatBots.Script> scripts_on_hold = new List<ChatBots.Script>();
|
||||||
public void BotLoad(ChatBot b) { b.SetHandler(this); bots.Add(b); b.Initialize(); Settings.SingleCommand = ""; }
|
public void BotLoad(ChatBot b) { b.SetHandler(this); bots.Add(b); b.Initialize(); Settings.SingleCommand = ""; }
|
||||||
public void BotUnLoad(ChatBot b) { bots.RemoveAll(item => object.ReferenceEquals(item, b)); }
|
public void BotUnLoad(ChatBot b) {
|
||||||
|
bots.RemoveAll(item => object.ReferenceEquals(item, b));
|
||||||
|
|
||||||
|
// ToList is needed to avoid an InvalidOperationException from modfiying the list while it's being iterated upon.
|
||||||
|
var botRegistrations = registeredBotPluginChannels.Where(entry => entry.Value.Contains(b)).ToList();
|
||||||
|
foreach (var entry in botRegistrations)
|
||||||
|
{
|
||||||
|
UnregisterPluginChannel(entry.Key, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
public void BotClear() { bots.Clear(); }
|
public void BotClear() { bots.Clear(); }
|
||||||
|
|
||||||
|
private readonly Dictionary<string, List<ChatBot>> registeredBotPluginChannels = new Dictionary<string, List<ChatBot>>();
|
||||||
|
private readonly List<string> registeredServerPluginChannels = new List<String>();
|
||||||
|
|
||||||
private object locationLock = new object();
|
private object locationLock = new object();
|
||||||
private bool locationReceived = false;
|
private bool locationReceived = false;
|
||||||
private World world = new World();
|
private World world = new World();
|
||||||
|
|
@ -573,5 +585,108 @@ namespace MinecraftClient
|
||||||
return onlinePlayers.Values.Distinct().ToArray();
|
return onlinePlayers.Values.Distinct().ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers the given plugin channel for the given bot.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The channel to register.</param>
|
||||||
|
/// <param name="bot">The bot to register the channel for.</param>
|
||||||
|
|
||||||
|
public void RegisterPluginChannel(string channel, ChatBot bot)
|
||||||
|
{
|
||||||
|
if (registeredBotPluginChannels.ContainsKey(channel))
|
||||||
|
{
|
||||||
|
registeredBotPluginChannels[channel].Add(bot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<ChatBot> bots = new List<ChatBot>();
|
||||||
|
bots.Add(bot);
|
||||||
|
registeredBotPluginChannels[channel] = bots;
|
||||||
|
SendPluginChannelMessage("REGISTER", Encoding.UTF8.GetBytes(channel), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unregisters the given plugin channel for the given bot.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The channel to unregister.</param>
|
||||||
|
/// <param name="bot">The bot to unregister the channel for.</param>
|
||||||
|
|
||||||
|
public void UnregisterPluginChannel(string channel, ChatBot bot)
|
||||||
|
{
|
||||||
|
if (registeredBotPluginChannels.ContainsKey(channel))
|
||||||
|
{
|
||||||
|
List<ChatBot> registeredBots = registeredBotPluginChannels[channel];
|
||||||
|
registeredBots.RemoveAll(item => object.ReferenceEquals(item, bot));
|
||||||
|
if (registeredBots.Count == 0)
|
||||||
|
{
|
||||||
|
registeredBotPluginChannels.Remove(channel);
|
||||||
|
SendPluginChannelMessage("UNREGISTER", Encoding.UTF8.GetBytes(channel), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a plugin channel packet to the server. See http://wiki.vg/Plugin_channel for more information
|
||||||
|
/// about plugin channels.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The channel to send the packet on.</param>
|
||||||
|
/// <param name="data">The payload for the packet.</param>
|
||||||
|
/// <param name="sendEvenIfNotRegistered">Whether the packet should be sent even if the server or the client hasn't registered it yet.</param>
|
||||||
|
/// <returns>Whether the packet was sent: true if it was sent, false if there was a connection error or it wasn't registered.</returns>
|
||||||
|
|
||||||
|
public bool SendPluginChannelMessage(string channel, byte[] data, bool sendEvenIfNotRegistered = false)
|
||||||
|
{
|
||||||
|
if (!sendEvenIfNotRegistered)
|
||||||
|
{
|
||||||
|
if (!registeredBotPluginChannels.ContainsKey(channel))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!registeredServerPluginChannels.Contains(channel))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handler.SendPluginChannelPacket(channel, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a plugin channel message was sent from the server.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The channel the message was sent on</param>
|
||||||
|
/// <param name="data">The data from the channel</param>
|
||||||
|
|
||||||
|
public void OnPluginChannelMessage(string channel, byte[] data)
|
||||||
|
{
|
||||||
|
if (channel == "REGISTER")
|
||||||
|
{
|
||||||
|
string[] channels = Encoding.UTF8.GetString(data).Split('\0');
|
||||||
|
foreach (string chan in channels)
|
||||||
|
{
|
||||||
|
if (!registeredServerPluginChannels.Contains(chan))
|
||||||
|
{
|
||||||
|
registeredServerPluginChannels.Add(chan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (channel == "UNREGISTER")
|
||||||
|
{
|
||||||
|
string[] channels = Encoding.UTF8.GetString(data).Split('\0');
|
||||||
|
foreach (string chan in channels)
|
||||||
|
{
|
||||||
|
registeredServerPluginChannels.Remove(chan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registeredBotPluginChannels.ContainsKey(channel))
|
||||||
|
{
|
||||||
|
foreach (ChatBot bot in registeredBotPluginChannels[channel])
|
||||||
|
{
|
||||||
|
bot.OnPluginMessage(channel, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,10 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
case 0xCF: if (protocolversion > 51) { readNextString(); readData(1); readNextString(); } readData(4); break;
|
case 0xCF: if (protocolversion > 51) { readNextString(); readData(1); readNextString(); } readData(4); break;
|
||||||
case 0xD0: if (protocolversion > 51) { readData(1); readNextString(); } break;
|
case 0xD0: if (protocolversion > 51) { readData(1); readNextString(); } break;
|
||||||
case 0xD1: if (protocolversion > 51) { readNextTeamData(); } break;
|
case 0xD1: if (protocolversion > 51) { readNextTeamData(); } break;
|
||||||
case 0xFA: readNextString(); nbr = readNextShort(); readData(nbr); break;
|
case 0xFA: string channel = readNextString();
|
||||||
|
byte[] payload = readNextByteArray();
|
||||||
|
handler.OnPluginChannelMessage(channel, payload);
|
||||||
|
break;
|
||||||
case 0xFF: string reason = readNextString();
|
case 0xFF: string reason = readNextString();
|
||||||
handler.OnConnectionLost(ChatBot.DisconnectReason.InGameKick, reason); break;
|
handler.OnConnectionLost(ChatBot.DisconnectReason.InGameKick, reason); break;
|
||||||
default: return false; //unknown packet!
|
default: return false; //unknown packet!
|
||||||
|
|
|
||||||
|
|
@ -303,6 +303,10 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
readNextVarShort(packetData);
|
readNextVarShort(packetData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The remaining data in the array is the entire payload of the packet.
|
||||||
|
handler.OnPluginChannelMessage(channel, packetData.ToArray());
|
||||||
|
|
||||||
if (forgeInfo != null)
|
if (forgeInfo != null)
|
||||||
{
|
{
|
||||||
if (channel == "FML|HS")
|
if (channel == "FML|HS")
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ namespace MinecraftClient.Protocol
|
||||||
|
|
||||||
public interface IMinecraftComHandler
|
public interface IMinecraftComHandler
|
||||||
{
|
{
|
||||||
/* The MinecraftCom Hanler must
|
/* The MinecraftCom Handler must
|
||||||
* provide these getters */
|
* provide these getters */
|
||||||
|
|
||||||
int GetServerPort();
|
int GetServerPort();
|
||||||
|
|
@ -72,5 +72,40 @@ namespace MinecraftClient.Protocol
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
void OnUpdate();
|
void OnUpdate();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers the given plugin channel for the given bot.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The channel to register.</param>
|
||||||
|
/// <param name="bot">The bot to register the channel for.</param>
|
||||||
|
|
||||||
|
void RegisterPluginChannel(string channel, ChatBot bot);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unregisters the given plugin channel for the given bot.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The channel to unregister.</param>
|
||||||
|
/// <param name="bot">The bot to unregister the channel for.</param>
|
||||||
|
|
||||||
|
void UnregisterPluginChannel(string channel, ChatBot bot);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a plugin channel packet to the server. See http://wiki.vg/Plugin_channel for more information
|
||||||
|
/// about plugin channels.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The channel to send the packet on.</param>
|
||||||
|
/// <param name="data">The payload for the packet.</param>
|
||||||
|
/// <param name="sendEvenIfNotRegistered">Whether the packet should be sent even if the server or the client hasn't registered it yet.</param>
|
||||||
|
/// <returns>Whether the packet was sent: true if it was sent, false if there was a connection error or it wasn't registered.</returns>
|
||||||
|
|
||||||
|
bool SendPluginChannelMessage(string channel, byte[] data, bool sendEvenIfNotRegistered = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a plugin channel message was sent from the server.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The channel the message was sent on</param>
|
||||||
|
/// <param name="data">The data from the channel</param>
|
||||||
|
|
||||||
|
void OnPluginChannelMessage(string channel, byte[] data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue