2020-05-26 00:16:53 +05:00
using System ;
2014-05-31 01:59:03 +02:00
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
2014-07-20 12:02:17 +02:00
using System.IO ;
2015-06-20 22:58:18 +02:00
using System.Threading ;
2015-10-22 22:17:15 +02:00
using System.Text.RegularExpressions ;
2020-03-26 15:01:42 +08:00
using MinecraftClient.Inventory ;
2020-05-29 23:18:34 +05:00
using MinecraftClient.Mapping ;
2014-05-31 01:59:03 +02:00
namespace MinecraftClient
{
///
/// Welcome to the Bot API file !
/// The virtual class "ChatBot" contains anything you need for creating chat bots
2016-09-11 20:11:01 +02:00
/// Inherit from this class while adding your bot class to the "ChatBots" folder.
2014-06-18 13:32:17 +02:00
/// Override the methods you want for handling events: Initialize, Update, GetText.
2014-05-31 01:59:03 +02:00
///
2016-09-11 20:11:01 +02:00
/// For testing your bot you can add it in McTcpClient.cs (see comment at line ~119).
/// Your bot will be loaded everytime MCC is started so that you can test/debug.
///
/// Once your bot is fully written and tested, you can export it a standalone script.
/// This way it can be loaded in newer MCC builds, without modifying MCC itself.
/// See config/sample-script-with-chatbot.cs for a ChatBot script example.
2014-05-31 01:59:03 +02:00
///
/// <summary>
/// The virtual class containing anything you need for creating chat bots.
/// </summary>
public abstract class ChatBot
{
2019-12-08 22:24:20 +01:00
public enum DisconnectReason { InGameKick , LoginRejected , ConnectionLost , UserLogout } ;
2014-05-31 01:59:03 +02:00
2015-06-21 18:45:43 +02:00
//Handler will be automatically set on bot loading, don't worry about this
2020-06-20 15:01:16 +02:00
public void SetHandler ( McClient handler ) { this . _handler = handler ; }
2015-06-21 18:45:43 +02:00
protected void SetMaster ( ChatBot master ) { this . master = master ; }
protected void LoadBot ( ChatBot bot ) { Handler . BotUnLoad ( bot ) ; Handler . BotLoad ( bot ) ; }
2020-06-20 15:01:16 +02:00
private McClient _handler = null ;
2015-06-20 22:58:18 +02:00
private ChatBot master = null ;
2016-02-07 14:24:01 -08:00
private List < string > registeredPluginChannels = new List < String > ( ) ;
2016-01-29 16:11:26 -08:00
private Queue < string > chatQueue = new Queue < string > ( ) ;
2016-02-27 17:59:08 +01:00
private DateTime lastMessageSentTime = DateTime . MinValue ;
2020-06-20 15:01:16 +02:00
private McClient Handler
2017-03-13 22:11:04 +01:00
{
get
{
if ( master ! = null )
return master . Handler ;
if ( _handler ! = null )
return _handler ;
throw new InvalidOperationException (
"ChatBot methods should NOT be called in the constructor as API handler is not initialized yet."
+ " Override Initialize() or AfterGameJoined() instead to perform initialization tasks." ) ;
}
}
private bool MessageCooldownEnded
2016-01-29 16:11:26 -08:00
{
get
{
2016-02-27 17:59:08 +01:00
return DateTime . Now > lastMessageSentTime + Settings . botMessageDelay ;
2016-01-29 16:11:26 -08:00
}
}
/// <summary>
/// Processes the current chat message queue, displaying a message after enough time passes.
/// </summary>
internal void ProcessQueuedText ( )
{
if ( chatQueue . Count > 0 )
{
2017-03-13 22:11:04 +01:00
if ( MessageCooldownEnded )
2016-01-29 16:11:26 -08:00
{
string text = chatQueue . Dequeue ( ) ;
LogToConsole ( "Sending '" + text + "'" ) ;
lastMessageSentTime = DateTime . Now ;
Handler . SendText ( text ) ;
}
}
}
2014-05-31 01:59:03 +02:00
/* ================================================== */
/* Main methods to override for creating your bot */
/* ================================================== */
/// <summary>
/// Anything you want to initialize your bot, will be called on load by MinecraftCom
2017-03-13 22:11:04 +01:00
/// This method is called only once, whereas AfterGameJoined() is called once per server join.
2016-02-07 14:47:03 -08:00
///
2017-03-13 22:11:04 +01:00
/// NOTE: Chat messages cannot be sent at this point in the login process.
/// If you want to send a message when the bot is loaded, use AfterGameJoined.
2014-05-31 01:59:03 +02:00
/// </summary>
public virtual void Initialize ( ) { }
2016-02-07 14:47:03 -08:00
/// <summary>
/// Called after the server has been joined successfully and chat messages are able to be sent.
2017-03-13 22:11:04 +01:00
/// This method is called again after reconnecting to the server, whereas Initialize() is called only once.
2016-02-07 14:47:03 -08:00
///
/// NOTE: This is not always right after joining the server - if the bot was loaded after logging
/// in this is still called.
/// </summary>
public virtual void AfterGameJoined ( ) { }
2014-05-31 01:59:03 +02:00
/// <summary>
/// Will be called every ~100ms (10fps) if loaded in MinecraftCom
/// </summary>
public virtual void Update ( ) { }
/// <summary>
/// Any text sent by the server will be sent here by MinecraftCom
/// </summary>
/// <param name="text">Text from the server</param>
public virtual void GetText ( string text ) { }
2017-05-31 20:54:16 +02:00
/// <summary>
/// Any text sent by the server will be sent here by MinecraftCom (extended variant)
/// </summary>
/// <remarks>
/// You can use Json.ParseJson() to process the JSON string.
/// </remarks>
/// <param name="text">Text from the server</param>
/// <param name="json">Raw JSON from the server. This parameter will be NULL on MC 1.5 or lower!</param>
public virtual void GetText ( string text , string json ) { }
2020-07-04 13:45:51 +05:00
2014-05-31 01:59:03 +02:00
/// <summary>
/// Is called when the client has been disconnected fom the server
/// </summary>
/// <param name="reason">Disconnect Reason</param>
/// <param name="message">Kick message, if any</param>
/// <returns>Return TRUE if the client is about to restart</returns>
public virtual bool OnDisconnect ( DisconnectReason reason , string message ) { return false ; }
2016-02-07 14:24:01 -08:00
/// <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 ) { }
2020-03-27 21:14:05 +01:00
/// <summary>
/// Called when properties for the Player entity are received from the server
/// </summary>
/// <param name="prop">Dictionary of player properties</param>
2020-03-23 19:59:00 +08:00
public virtual void OnPlayerProperty ( Dictionary < string , Double > prop ) { }
2020-03-27 21:14:05 +01:00
/// <summary>
/// Called when server TPS are recalculated by MCC based on world time updates
/// </summary>
/// <param name="tps">New estimated server TPS (between 0 and 20)</param>
2020-03-23 19:59:00 +08:00
public virtual void OnServerTpsUpdate ( Double tps ) { }
2020-03-27 21:14:05 +01:00
/// <summary>
/// Called when an entity moved nearby
/// </summary>
/// <param name="entity">Entity with updated location</param>
2020-03-23 19:59:00 +08:00
public virtual void OnEntityMove ( Mapping . Entity entity ) { }
2020-05-29 23:18:34 +05:00
/// <summary>
/// Called after an internal MCC command has been performed
/// </summary>
/// <param name="commandName">MCC Command Name</param>
/// <param name="commandParams">MCC Command Parameters</param>
/// <param name="Result">MCC command result</param>
public virtual void OnInternalCommand ( string commandName , string commandParams , string Result ) { }
2020-05-01 09:37:15 -05:00
2020-03-27 21:14:05 +01:00
/// <summary>
/// Called when an entity spawned nearby
/// </summary>
/// <param name="entity">New Entity</param>
2020-03-23 19:59:00 +08:00
public virtual void OnEntitySpawn ( Mapping . Entity entity ) { }
2020-03-27 21:14:05 +01:00
/// <summary>
/// Called when an entity despawns/dies nearby
/// </summary>
/// <param name="entity">Entity wich has just disappeared</param>
2020-03-24 15:03:32 +08:00
public virtual void OnEntityDespawn ( Mapping . Entity entity ) { }
2020-03-23 19:59:00 +08:00
2020-05-01 14:02:23 +02:00
/// <summary>
/// Called when the player held item has changed
/// </summary>
/// <param name="slot">New slot ID</param>
2020-04-08 18:23:19 +08:00
public virtual void OnHeldItemChange ( byte slot ) { }
2020-05-01 14:02:23 +02:00
/// <summary>
/// Called when the player health has been updated
/// </summary>
/// <param name="health">New player health</param>
/// <param name="food">New food level</param>
2020-04-08 18:23:19 +08:00
public virtual void OnHealthUpdate ( float health , int food ) { }
2020-05-29 23:18:34 +05:00
/// <summary>
/// Called when an explosion occurs on the server
/// </summary>
/// <param name="explode">Explosion location</param>
/// <param name="recordcount">Amount of blocks blown up</param>
public virtual void OnExplosion ( Location explode , float strength , int recordcount ) { }
/// <summary>
/// Called when experience updates
/// </summary>
/// <param name="Experiencebar">Between 0 and 1</param>
/// <param name="Level">Level</param>
/// <param name="TotalExperience">Total Experience</param>
public virtual void OnSetExperience ( float Experiencebar , int Level , int TotalExperience ) { }
/// <summary>
/// Called when the Game Mode has been updated for a player
/// </summary>
/// <param name="playername">Player Name</param>
/// <param name="uuid">Player UUID</param>
/// <param name="gamemode">New Game Mode (0: Survival, 1: Creative, 2: Adventure, 3: Spectator).</param>
public virtual void OnGamemodeUpdate ( string playername , Guid uuid , int gamemode ) { }
2020-06-07 16:16:49 +05:00
/// <summary>
/// Called when the Latency has been updated for a player
/// </summary>
/// <param name="playername">Player Name</param>
/// <param name="uuid">Player UUID</param>
/// <param name="latency">Latency.</param>
public virtual void OnLatencyUpdate ( string playername , Guid uuid , int latency ) { }
2020-06-20 17:57:07 +05:00
/// <summary>
/// Called map data
/// </summary>
/// <param name="mapid"></param>
/// <param name="scale"></param>
/// <param name="trackingposition"></param>
/// <param name="locked"></param>
/// <param name="iconcount"></param>
public virtual void OnMapData ( int mapid , byte scale , bool trackingposition , bool locked , int iconcount ) { }
/// <summary>
/// Received some Title from the server
/// <param name="action"> 0 = set title, 1 = set subtitle, 3 = set action bar, 4 = set times and display, 4 = hide, 5 = reset</param>
/// <param name="titletext"> title text</param>
/// <param name="subtitletext"> suntitle text</param>
/// <param name="actionbartext"> action bar text</param>
/// <param name="fadein"> Fade In</param>
/// <param name="stay"> Stay</param>
/// <param name="fadeout"> Fade Out</param>
/// <param name="json"> json text</param>
public virtual void OnTitle ( int action , string titletext , string subtitletext , string actionbartext , int fadein , int stay , int fadeout , string json ) { }
/// <summary>
/// Called on Entity Equipment
/// </summary>
/// <param name="entity"> Entity</param>
/// <param name="slot"> Equipment slot. 0: main hand, 1: off hand, 2– 5: armor slot (2: boots, 3: leggings, 4: chestplate, 5: helmet)</param>
/// <param name="item"> Item)</param>
public virtual void OnEntityEquipment ( Entity entity , int slot , Item item ) { }
2020-07-04 13:45:51 +05:00
/// <summary>
/// Called when the Entity use effects
/// </summary>
/// <param name="entityid">entity ID</param>
/// <param name="effect">effect id</param>
/// <param name="amplifier">effect amplifier</param>
/// <param name="duration">effect duration</param>
/// <param name="flags">effect flags</param>
public virtual void OnEntityEffect ( Entity entity , Effects effect , int amplifier , int duration , byte flags ) { }
/// <summary>
/// Called when coreboardObjective
/// </summary>
/// <param name="objectivename">objective name</param>
/// <param name="mode">0 to create the scoreboard. 1 to remove the scoreboard. 2 to update the display text.</param>
/// <param name="objectivevalue">Only if mode is 0 or 2. The text to be displayed for the score</param>
/// <param name="type">Only if mode is 0 or 2. 0 = "integer", 1 = "hearts".</param>
public virtual void OnScoreboardObjective ( string objectivename , byte mode , string objectivevalue , int type , string json ) { }
/// <summary>
/// Called when DisplayScoreboard
/// </summary>
/// <param name="entityname">The entity whose score this is. For players, this is their username; for other entities, it is their UUID.</param>
/// <param name="action">0 to create/update an item. 1 to remove an item.</param>
/// <param name="objectivename">The name of the objective the score belongs to</param>
/// <param name="value">he score to be displayed next to the entry. Only sent when Action does not equal 1.</param>
public virtual void OnUpdateScore ( string entityname , byte action , string objectivename , int value ) { }
2020-05-29 23:18:34 +05:00
2014-05-31 01:59:03 +02:00
/* =================================================================== */
/* ToolBox - Methods below might be useful while creating your bot. */
/* You should not need to interact with other classes of the program. */
2014-07-20 12:02:17 +02:00
/* All the methods in this ChatBot class should do the job for you. */
2014-05-31 01:59:03 +02:00
/* =================================================================== */
/// <summary>
/// Send text to the server. Can be anything such as chat messages or commands
/// </summary>
/// <param name="text">Text to send to the server</param>
2016-01-29 16:11:26 -08:00
/// <param name="sendImmediately">Whether the message should be sent immediately rather than being queued to avoid chat spam</param>
2014-06-14 13:20:15 +02:00
/// <returns>True if the text was sent with no error</returns>
2016-01-29 16:11:26 -08:00
protected bool SendText ( string text , bool sendImmediately = false )
2014-05-31 01:59:03 +02:00
{
2016-01-29 16:11:26 -08:00
if ( Settings . botMessageDelay . TotalSeconds > 0 & & ! sendImmediately )
{
2017-03-13 22:11:04 +01:00
if ( ! MessageCooldownEnded )
2016-01-29 16:11:26 -08:00
{
chatQueue . Enqueue ( text ) ;
// TODO: We don't know whether there was an error at this point, so we assume there isn't.
// Might not be the best idea.
return true ;
}
}
2014-07-20 12:02:17 +02:00
LogToConsole ( "Sending '" + text + "'" ) ;
2016-01-29 16:11:26 -08:00
lastMessageSentTime = DateTime . Now ;
2015-08-23 18:51:24 +02:00
return Handler . SendText ( text ) ;
2014-06-14 13:20:15 +02:00
}
/// <summary>
2014-06-14 18:48:43 +02:00
/// Perform an internal MCC command (not a server command, use SendText() instead for that!)
2014-06-14 13:20:15 +02:00
/// </summary>
2014-06-14 18:48:43 +02:00
/// <param name="command">The command to process</param>
2020-03-27 21:14:05 +01:00
/// <param name="localVars">Local variables passed along with the command</param>
2014-06-14 18:48:43 +02:00
/// <returns>TRUE if the command was indeed an internal MCC command</returns>
2020-03-27 21:14:05 +01:00
protected bool PerformInternalCommand ( string command , Dictionary < string , object > localVars = null )
2014-06-14 13:20:15 +02:00
{
2014-06-14 18:48:43 +02:00
string temp = "" ;
2020-03-27 21:14:05 +01:00
return Handler . PerformInternalCommand ( command , ref temp , localVars ) ;
2014-06-14 13:20:15 +02:00
}
/// <summary>
/// Perform an internal MCC command (not a server command, use SendText() instead for that!)
/// </summary>
2014-06-14 18:48:43 +02:00
/// <param name="command">The command to process</param>
/// <param name="response_msg">May contain a confirmation or error message after processing the command, or "" otherwise.</param>
2020-03-27 21:14:05 +01:00
/// <param name="localVars">Local variables passed along with the command</param>
2014-06-14 18:48:43 +02:00
/// <returns>TRUE if the command was indeed an internal MCC command</returns>
2020-03-27 21:14:05 +01:00
protected bool PerformInternalCommand ( string command , ref string response_msg , Dictionary < string , object > localVars = null )
2014-06-14 13:20:15 +02:00
{
2020-03-27 21:14:05 +01:00
return Handler . PerformInternalCommand ( command , ref response_msg , localVars ) ;
2014-05-31 01:59:03 +02:00
}
/// <summary>
/// Remove color codes ("§c") from a text message received from the server
/// </summary>
2020-05-14 13:36:56 -04:00
public static string GetVerbatim ( string text )
2014-05-31 01:59:03 +02:00
{
if ( String . IsNullOrEmpty ( text ) )
return String . Empty ;
int idx = 0 ;
var data = new char [ text . Length ] ;
for ( int i = 0 ; i < text . Length ; i + + )
if ( text [ i ] ! = '§' )
data [ idx + + ] = text [ i ] ;
else
i + + ;
return new string ( data , 0 , idx ) ;
}
/// <summary>
/// Verify that a string contains only a-z A-Z 0-9 and _ characters.
/// </summary>
2016-08-22 23:15:16 +02:00
public static bool IsValidName ( string username )
2014-05-31 01:59:03 +02:00
{
2015-10-22 22:17:15 +02:00
if ( String . IsNullOrEmpty ( username ) )
2014-05-31 01:59:03 +02:00
return false ;
2015-10-22 22:17:15 +02:00
foreach ( char c in username )
if ( ! ( ( c > = 'a' & & c < = 'z' )
2014-05-31 01:59:03 +02:00
| | ( c > = 'A' & & c < = 'Z' )
| | ( c > = '0' & & c < = '9' )
| | c = = '_' ) )
return false ;
return true ;
}
/// <summary>
2014-06-14 13:51:30 +02:00
/// Returns true if the text passed is a private message sent to the bot
2014-05-31 01:59:03 +02:00
/// </summary>
/// <param name="text">text to test</param>
/// <param name="message">if it's a private message, this will contain the message</param>
/// <param name="sender">if it's a private message, this will contain the player name that sends the message</param>
/// <returns>Returns true if the text is a private message</returns>
2015-06-20 22:58:18 +02:00
protected static bool IsPrivateMessage ( string text , ref string message , ref string sender )
2014-05-31 01:59:03 +02:00
{
2015-10-22 22:17:15 +02:00
if ( String . IsNullOrEmpty ( text ) )
return false ;
2015-06-20 22:58:18 +02:00
text = GetVerbatim ( text ) ;
2014-05-31 01:59:03 +02:00
2019-04-17 05:32:31 +02:00
//User-defined regex for private chat messages
if ( Settings . ChatFormat_Private ! = null )
{
Match regexMatch = Settings . ChatFormat_Private . Match ( text ) ;
if ( regexMatch . Success & & regexMatch . Groups . Count > = 3 )
{
sender = regexMatch . Groups [ 1 ] . Value ;
message = regexMatch . Groups [ 2 ] . Value ;
return IsValidName ( sender ) ;
}
}
2015-10-22 22:17:15 +02:00
//Built-in detection routine for private messages
if ( Settings . ChatFormat_Builtins )
2014-05-31 01:59:03 +02:00
{
2015-10-22 22:17:15 +02:00
string [ ] tmp = text . Split ( ' ' ) ;
try
2014-05-31 01:59:03 +02:00
{
2015-10-22 22:17:15 +02:00
//Detect vanilla /tell messages
//Someone whispers message (MC 1.5)
//Someone whispers to you: message (MC 1.7)
if ( tmp . Length > 2 & & tmp [ 1 ] = = "whispers" )
2014-06-03 13:05:53 +02:00
{
2015-10-22 22:17:15 +02:00
if ( tmp . Length > 4 & & tmp [ 2 ] = = "to" & & tmp [ 3 ] = = "you:" )
{
message = text . Substring ( tmp [ 0 ] . Length + 18 ) ; //MC 1.7
}
else message = text . Substring ( tmp [ 0 ] . Length + 10 ) ; //MC 1.5
sender = tmp [ 0 ] ;
return IsValidName ( sender ) ;
2014-06-03 13:05:53 +02:00
}
2014-05-31 01:59:03 +02:00
2015-10-22 22:17:15 +02:00
//Detect Essentials (Bukkit) /m messages
//[Someone -> me] message
//[~Someone -> me] message
else if ( text [ 0 ] = = '[' & & tmp . Length > 3 & & tmp [ 1 ] = = "->"
2016-02-27 17:56:47 +01:00
& & ( tmp [ 2 ] . ToLower ( ) = = "me]" | | tmp [ 2 ] . ToLower ( ) = = "moi]" ) ) //'me' is replaced by 'moi' in french servers
2015-10-22 22:17:15 +02:00
{
message = text . Substring ( tmp [ 0 ] . Length + 4 + tmp [ 2 ] . Length + 1 ) ;
sender = tmp [ 0 ] . Substring ( 1 ) ;
if ( sender [ 0 ] = = '~' ) { sender = sender . Substring ( 1 ) ; }
return IsValidName ( sender ) ;
}
2014-07-29 17:08:24 +02:00
2015-10-22 22:17:15 +02:00
//Detect Modified server messages. /m
//[Someone @ me] message
else if ( text [ 0 ] = = '[' & & tmp . Length > 3 & & tmp [ 1 ] = = "@"
2016-02-27 17:56:47 +01:00
& & ( tmp [ 2 ] . ToLower ( ) = = "me]" | | tmp [ 2 ] . ToLower ( ) = = "moi]" ) ) //'me' is replaced by 'moi' in french servers
2015-10-22 22:17:15 +02:00
{
message = text . Substring ( tmp [ 0 ] . Length + 4 + tmp [ 2 ] . Length + 0 ) ;
sender = tmp [ 0 ] . Substring ( 1 ) ;
if ( sender [ 0 ] = = '~' ) { sender = sender . Substring ( 1 ) ; }
return IsValidName ( sender ) ;
}
2015-09-02 23:01:46 -04:00
2015-10-22 22:17:15 +02:00
//Detect Essentials (Bukkit) /me messages with some custom prefix
//[Prefix] [Someone -> me] message
//[Prefix] [~Someone -> me] message
else if ( text [ 0 ] = = '[' & & tmp [ 0 ] [ tmp [ 0 ] . Length - 1 ] = = ']'
& & tmp [ 1 ] [ 0 ] = = '[' & & tmp . Length > 4 & & tmp [ 2 ] = = "->"
2016-02-27 17:56:47 +01:00
& & ( tmp [ 3 ] . ToLower ( ) = = "me]" | | tmp [ 3 ] . ToLower ( ) = = "moi]" ) )
2015-10-22 22:17:15 +02:00
{
message = text . Substring ( tmp [ 0 ] . Length + 1 + tmp [ 1 ] . Length + 4 + tmp [ 3 ] . Length + 1 ) ;
sender = tmp [ 1 ] . Substring ( 1 ) ;
if ( sender [ 0 ] = = '~' ) { sender = sender . Substring ( 1 ) ; }
return IsValidName ( sender ) ;
}
2015-07-31 12:23:13 +02:00
2015-10-22 22:17:15 +02:00
//Detect Essentials (Bukkit) /me messages with some custom rank
//[Someone [rank] -> me] message
//[~Someone [rank] -> me] message
else if ( text [ 0 ] = = '[' & & tmp . Length > 3 & & tmp [ 2 ] = = "->"
2016-02-27 17:56:47 +01:00
& & ( tmp [ 3 ] . ToLower ( ) = = "me]" | | tmp [ 3 ] . ToLower ( ) = = "moi]" ) )
2015-10-22 22:17:15 +02:00
{
message = text . Substring ( tmp [ 0 ] . Length + 1 + tmp [ 1 ] . Length + 4 + tmp [ 2 ] . Length + 1 ) ;
sender = tmp [ 0 ] . Substring ( 1 ) ;
if ( sender [ 0 ] = = '~' ) { sender = sender . Substring ( 1 ) ; }
return IsValidName ( sender ) ;
}
//Detect HeroChat PMsend
//From Someone: message
else if ( text . StartsWith ( "From " ) )
{
sender = text . Substring ( 5 ) . Split ( ':' ) [ 0 ] ;
message = text . Substring ( text . IndexOf ( ':' ) + 2 ) ;
return IsValidName ( sender ) ;
}
else return false ;
2014-07-29 17:08:24 +02:00
}
2015-10-22 22:17:15 +02:00
catch ( IndexOutOfRangeException ) { /* Not an expected chat format */ }
2016-01-26 10:35:44 +01:00
catch ( ArgumentOutOfRangeException ) { /* Same here */ }
2015-10-22 22:17:15 +02:00
}
2015-02-26 12:45:24 +01:00
2015-10-22 22:17:15 +02:00
return false ;
2014-05-31 01:59:03 +02:00
}
/// <summary>
2014-06-14 13:51:30 +02:00
/// Returns true if the text passed is a public message written by a player on the chat
2014-05-31 01:59:03 +02:00
/// </summary>
/// <param name="text">text to test</param>
/// <param name="message">if it's message, this will contain the message</param>
/// <param name="sender">if it's message, this will contain the player name that sends the message</param>
/// <returns>Returns true if the text is a chat message</returns>
2015-06-20 22:58:18 +02:00
protected static bool IsChatMessage ( string text , ref string message , ref string sender )
2014-05-31 01:59:03 +02:00
{
2015-10-22 22:17:15 +02:00
if ( String . IsNullOrEmpty ( text ) )
return false ;
2015-06-20 22:58:18 +02:00
text = GetVerbatim ( text ) ;
2019-04-17 05:32:31 +02:00
//User-defined regex for public chat messages
if ( Settings . ChatFormat_Public ! = null )
{
Match regexMatch = Settings . ChatFormat_Public . Match ( text ) ;
if ( regexMatch . Success & & regexMatch . Groups . Count > = 3 )
{
sender = regexMatch . Groups [ 1 ] . Value ;
message = regexMatch . Groups [ 2 ] . Value ;
return IsValidName ( sender ) ;
}
}
2015-10-22 22:17:15 +02:00
//Built-in detection routine for public messages
if ( Settings . ChatFormat_Builtins )
2014-05-31 01:59:03 +02:00
{
2015-10-22 22:17:15 +02:00
string [ ] tmp = text . Split ( ' ' ) ;
2015-05-18 16:15:58 +02:00
//Detect vanilla/factions Messages
//<Someone> message
//<*Faction Someone> message
//<*Faction Someone>: message
//<*Faction ~Nicknamed>: message
2015-10-22 22:17:15 +02:00
if ( text [ 0 ] = = '<' )
2014-05-31 01:59:03 +02:00
{
2015-05-18 16:15:58 +02:00
try
{
text = text . Substring ( 1 ) ;
string [ ] tmp2 = text . Split ( '>' ) ;
sender = tmp2 [ 0 ] ;
message = text . Substring ( sender . Length + 2 ) ;
if ( message . Length > 1 & & message [ 0 ] = = ' ' )
{ message = message . Substring ( 1 ) ; }
tmp2 = sender . Split ( ' ' ) ;
sender = tmp2 [ tmp2 . Length - 1 ] ;
if ( sender [ 0 ] = = '~' ) { sender = sender . Substring ( 1 ) ; }
2015-06-20 22:58:18 +02:00
return IsValidName ( sender ) ;
2015-05-18 16:15:58 +02:00
}
2015-10-26 23:19:06 +01:00
catch ( IndexOutOfRangeException ) { /* Not a vanilla/faction message */ }
2016-01-26 10:35:44 +01:00
catch ( ArgumentOutOfRangeException ) { /* Same here */ }
2015-05-18 16:15:58 +02:00
}
//Detect HeroChat Messages
2015-09-03 23:42:01 -04:00
//Public chat messages
2015-05-18 16:15:58 +02:00
//[Channel] [Rank] User: Message
2015-10-22 22:17:15 +02:00
else if ( text [ 0 ] = = '[' & & text . Contains ( ':' ) & & tmp . Length > 2 )
2015-05-18 16:15:58 +02:00
{
2015-10-26 23:19:06 +01:00
try
{
int name_end = text . IndexOf ( ':' ) ;
int name_start = text . Substring ( 0 , name_end ) . LastIndexOf ( ']' ) + 2 ;
sender = text . Substring ( name_start , name_end - name_start ) ;
message = text . Substring ( name_end + 2 ) ;
return IsValidName ( sender ) ;
}
catch ( IndexOutOfRangeException ) { /* Not a herochat message */ }
2016-01-26 10:35:44 +01:00
catch ( ArgumentOutOfRangeException ) { /* Same here */ }
2014-05-31 01:59:03 +02:00
}
2015-07-31 12:23:13 +02:00
//Detect (Unknown Plugin) Messages
//**Faction<Rank> User : Message
else if ( text [ 0 ] = = '*'
& & text . Length > 1
& & text [ 1 ] ! = ' '
& & text . Contains ( '<' ) & & text . Contains ( '>' )
& & text . Contains ( ' ' ) & & text . Contains ( ':' )
& & text . IndexOf ( '*' ) < text . IndexOf ( '<' )
& & text . IndexOf ( '<' ) < text . IndexOf ( '>' )
& & text . IndexOf ( '>' ) < text . IndexOf ( ' ' )
2015-10-22 22:17:15 +02:00
& & text . IndexOf ( ' ' ) < text . IndexOf ( ':' ) )
2015-07-31 12:23:13 +02:00
{
2015-10-26 23:19:06 +01:00
try
2015-07-31 12:23:13 +02:00
{
2015-10-26 23:19:06 +01:00
string prefix = tmp [ 0 ] ;
string user = tmp [ 1 ] ;
string semicolon = tmp [ 2 ] ;
if ( prefix . All ( c = > char . IsLetterOrDigit ( c ) | | new char [ ] { '*' , '<' , '>' , '_' } . Contains ( c ) )
& & semicolon = = ":" )
{
message = text . Substring ( prefix . Length + user . Length + 4 ) ;
return IsValidName ( user ) ;
}
2015-07-31 12:23:13 +02:00
}
2015-10-26 23:19:06 +01:00
catch ( IndexOutOfRangeException ) { /* Not a <unknown plugin> message */ }
2016-01-26 10:35:44 +01:00
catch ( ArgumentOutOfRangeException ) { /* Same here */ }
2015-07-31 12:23:13 +02:00
}
2014-05-31 01:59:03 +02:00
}
2015-10-22 22:17:15 +02:00
2015-05-18 16:15:58 +02:00
return false ;
2014-05-31 01:59:03 +02:00
}
2014-06-14 13:51:30 +02:00
/// <summary>
/// Returns true if the text passed is a teleport request (Essentials)
/// </summary>
/// <param name="text">Text to parse</param>
/// <param name="sender">Will contain the sender's username, if it's a teleport request</param>
/// <returns>Returns true if the text is a teleport request</returns>
2015-06-20 22:58:18 +02:00
protected static bool IsTeleportRequest ( string text , ref string sender )
2014-06-14 13:51:30 +02:00
{
2015-10-22 22:17:15 +02:00
if ( String . IsNullOrEmpty ( text ) )
return false ;
2015-06-20 22:58:18 +02:00
text = GetVerbatim ( text ) ;
2015-10-22 22:17:15 +02:00
2019-04-17 05:32:31 +02:00
//User-defined regex for teleport requests
if ( Settings . ChatFormat_TeleportRequest ! = null )
{
Match regexMatch = Settings . ChatFormat_TeleportRequest . Match ( text ) ;
if ( regexMatch . Success & & regexMatch . Groups . Count > = 2 )
{
sender = regexMatch . Groups [ 1 ] . Value ;
return IsValidName ( sender ) ;
}
}
2015-10-22 22:17:15 +02:00
//Built-in detection routine for teleport requests
if ( Settings . ChatFormat_Builtins )
2014-06-14 13:51:30 +02:00
{
2015-10-22 22:17:15 +02:00
string [ ] tmp = text . Split ( ' ' ) ;
//Detect Essentials teleport requests, prossibly with
//nicknamed names or other modifications such as HeroChat
if ( text . EndsWith ( "has requested to teleport to you." )
| | text . EndsWith ( "has requested that you teleport to them." ) )
{
//<Rank> Username has requested...
//[Rank] Username has requested...
if ( ( ( tmp [ 0 ] . StartsWith ( "<" ) & & tmp [ 0 ] . EndsWith ( ">" ) )
| | ( tmp [ 0 ] . StartsWith ( "[" ) & & tmp [ 0 ] . EndsWith ( "]" ) ) )
& & tmp . Length > 1 )
sender = tmp [ 1 ] ;
//Username has requested...
else sender = tmp [ 0 ] ;
//~Username has requested...
if ( sender . Length > 1 & & sender [ 0 ] = = '~' )
sender = sender . Substring ( 1 ) ;
//Final check on username validity
return IsValidName ( sender ) ;
}
}
return false ;
2014-06-14 13:51:30 +02:00
}
2014-05-31 01:59:03 +02:00
/// <summary>
2015-06-21 16:40:13 +02:00
/// Write some text in the console. Nothing will be sent to the server.
2014-05-31 01:59:03 +02:00
/// </summary>
/// <param name="text">Log text to write</param>
2015-08-23 18:51:24 +02:00
protected void LogToConsole ( object text )
2014-05-31 01:59:03 +02:00
{
2015-06-21 16:40:13 +02:00
ConsoleIO . WriteLogLine ( String . Format ( "[{0}] {1}" , this . GetType ( ) . Name , text ) ) ;
2015-06-20 22:58:18 +02:00
string logfile = Settings . ExpandVars ( Settings . chatbotLogFile ) ;
2014-07-20 12:02:17 +02:00
2014-09-07 15:17:47 +02:00
if ( ! String . IsNullOrEmpty ( logfile ) )
2014-07-20 12:02:17 +02:00
{
2014-09-07 15:17:47 +02:00
if ( ! File . Exists ( logfile ) )
2014-07-20 12:02:17 +02:00
{
2014-09-07 15:17:47 +02:00
try { Directory . CreateDirectory ( Path . GetDirectoryName ( logfile ) ) ; }
2014-07-20 12:02:17 +02:00
catch { return ; /* Invalid path or access denied */ }
2014-09-07 15:17:47 +02:00
try { File . WriteAllText ( logfile , "" ) ; }
2014-07-20 12:02:17 +02:00
catch { return ; /* Invalid file name or access denied */ }
}
2015-06-20 22:58:18 +02:00
File . AppendAllLines ( logfile , new string [ ] { GetTimestamp ( ) + ' ' + text } ) ;
2014-07-20 12:02:17 +02:00
}
2014-05-31 01:59:03 +02:00
}
2017-03-14 22:04:35 +01:00
/// <summary>
/// Write some text in the console, but only if DebugMessages is enabled in INI file. Nothing will be sent to the server.
/// </summary>
/// <param name="text">Debug log text to write</param>
protected void LogDebugToConsole ( object text )
{
if ( Settings . DebugMessages )
LogToConsole ( text ) ;
}
2014-05-31 01:59:03 +02:00
/// <summary>
/// Disconnect from the server and restart the program
2015-05-18 16:15:58 +02:00
/// It will unload and reload all the bots and then reconnect to the server
2014-05-31 01:59:03 +02:00
/// </summary>
2019-10-03 09:46:08 +02:00
/// <param name="ExtraAttempts">In case of failure, maximum extra attempts before aborting</param>
2017-03-13 21:15:36 +01:00
/// <param name="delaySeconds">Optional delay, in seconds, before restarting</param>
protected void ReconnectToTheServer ( int ExtraAttempts = 3 , int delaySeconds = 0 )
2014-05-31 01:59:03 +02:00
{
2020-04-02 18:19:37 +02:00
if ( Settings . DebugMessages )
ConsoleIO . WriteLogLine ( String . Format ( "[{0}] Disconnecting and Reconnecting to the Server" , this . GetType ( ) . Name ) ) ;
2020-06-20 15:01:16 +02:00
McClient . ReconnectionAttemptsLeft = ExtraAttempts ;
2017-03-13 21:15:36 +01:00
Program . Restart ( delaySeconds ) ;
2014-05-31 01:59:03 +02:00
}
/// <summary>
/// Disconnect from the server and exit the program
/// </summary>
protected void DisconnectAndExit ( )
{
Program . Exit ( ) ;
}
/// <summary>
/// Unload the chatbot, and release associated memory.
/// </summary>
protected void UnloadBot ( )
{
2015-06-20 22:58:18 +02:00
Handler . BotUnLoad ( this ) ;
2014-05-31 01:59:03 +02:00
}
/// <summary>
/// Send a private message to a player
/// </summary>
/// <param name="player">Player name</param>
/// <param name="message">Message</param>
protected void SendPrivateMessage ( string player , string message )
{
2016-01-27 00:23:25 +01:00
SendText ( String . Format ( "/{0} {1} {2}" , Settings . PrivateMsgsCmdName , player , message ) ) ;
2014-05-31 01:59:03 +02:00
}
/// <summary>
/// Run a script from a file using a Scripting bot
/// </summary>
/// <param name="filename">File name</param>
/// <param name="playername">Player name to send error messages, if applicable</param>
2020-03-27 21:14:05 +01:00
/// <param name="localVars">Local variables for use in the Script</param>
protected void RunScript ( string filename , string playername = null , Dictionary < string , object > localVars = null )
2014-05-31 01:59:03 +02:00
{
2020-03-27 21:14:05 +01:00
Handler . BotLoad ( new ChatBots . Script ( filename , playername , localVars ) ) ;
2014-05-31 01:59:03 +02:00
}
2014-07-20 12:02:17 +02:00
2019-04-28 21:32:03 +02:00
/// <summary>
/// Check whether Terrain and Movements is enabled.
/// </summary>
/// <returns>Enable status.</returns>
public bool GetTerrainEnabled ( )
{
return Handler . GetTerrainEnabled ( ) ;
}
/// <summary>
/// Enable or disable Terrain and Movements.
/// Please note that Enabling will be deferred until next relog, respawn or world change.
/// </summary>
/// <param name="enabled">Enabled</param>
/// <returns>TRUE if the setting was applied immediately, FALSE if delayed.</returns>
public bool SetTerrainEnabled ( bool enabled )
{
return Handler . SetTerrainEnabled ( enabled ) ;
}
2020-03-23 19:59:00 +08:00
/// <summary>
/// Get entity handling status
/// </summary>
/// <returns></returns>
/// <remarks>Entity Handling cannot be enabled in runtime (or after joining server)</remarks>
public bool GetEntityHandlingEnabled ( )
{
return Handler . GetEntityHandlingEnabled ( ) ;
}
2020-05-02 03:52:17 -05:00
/// <summary>
2020-05-02 03:55:23 -05:00
/// start Sneaking
/// </summary>
2020-05-03 10:51:50 -05:00
protected bool Sneak ( bool on )
2020-05-02 03:55:23 -05:00
{
2020-05-03 11:21:34 -05:00
return SendEntityAction ( on ? Protocol . EntityActionType . StartSneaking : Protocol . EntityActionType . StopSneaking ) ;
2020-05-02 03:55:23 -05:00
}
2020-05-29 23:18:34 +05:00
2020-05-02 03:55:23 -05:00
/// <summary>
2020-05-02 03:53:39 -05:00
/// Send Entity Action
/// </summary>
2020-05-03 11:21:34 -05:00
private bool SendEntityAction ( Protocol . EntityActionType entityAction )
2020-05-02 03:53:39 -05:00
{
2020-06-20 15:18:34 +02:00
return Handler . SendEntityAction ( entityAction ) ;
2020-05-02 03:53:39 -05:00
}
2020-05-29 23:18:34 +05:00
/// <summary>
2020-06-20 21:30:23 +02:00
/// Attempt to dig a block at the specified location
2020-05-29 23:18:34 +05:00
/// </summary>
2020-06-20 16:07:54 +02:00
/// <param name="location">Location</param>
2020-06-20 21:30:23 +02:00
protected bool DigBlock ( Location location )
2020-05-29 23:18:34 +05:00
{
2020-06-20 21:30:23 +02:00
return Handler . DigBlock ( location ) ;
2020-05-29 23:18:34 +05:00
}
2020-05-02 03:53:39 -05:00
/// <summary>
2020-05-02 03:52:17 -05:00
/// SetSlot
/// </summary>
protected void SetSlot ( int slotNum )
{
2020-06-14 15:41:34 +02:00
Handler . ChangeSlot ( ( short ) slotNum ) ;
2020-05-02 03:52:17 -05:00
}
2020-03-26 15:01:42 +08:00
2016-01-16 17:51:08 +01:00
/// <summary>
/// Get the current Minecraft World
/// </summary>
/// <returns>Minecraft world or null if associated setting is disabled</returns>
protected Mapping . World GetWorld ( )
{
2019-04-28 21:32:03 +02:00
if ( GetTerrainEnabled ( ) )
2016-01-16 17:51:08 +01:00
return Handler . GetWorld ( ) ;
return null ;
}
2020-07-04 13:45:51 +05:00
/// <summary>
/// Get all Entityes
/// </summary>
/// <returns>All Entities</returns>
protected Dictionary < int , Entity > GetEntities ( )
{
return Handler . GetEntities ( ) ;
}
2016-01-16 17:51:08 +01:00
2016-05-04 23:47:08 +02:00
/// <summary>
/// Get the current location of the player
/// </summary>
/// <returns>Minecraft world or null if associated setting is disabled</returns>
protected Mapping . Location GetCurrentLocation ( )
{
return Handler . GetCurrentLocation ( ) ;
}
/// <summary>
/// Move to the specified location
/// </summary>
/// <param name="location">Location to reach</param>
2020-06-14 15:41:34 +02:00
/// <param name="allowUnsafe">Allow possible but unsafe locations thay may hurt the player: lava, cactus...</param>
2020-07-04 11:12:23 +02:00
/// <param name="allowDirectTeleport">Allow non-vanilla teleport instead of computing path, but may cause invalid moves and/or trigger anti-cheat plugins</param>
2016-05-04 23:47:08 +02:00
/// <returns>True if a path has been found</returns>
2020-07-04 11:12:23 +02:00
protected bool MoveToLocation ( Mapping . Location location , bool allowUnsafe = false , bool allowDirectTeleport = false )
2016-05-04 23:47:08 +02:00
{
2020-07-04 11:12:23 +02:00
return Handler . MoveTo ( location , allowUnsafe , allowDirectTeleport ) ;
2016-05-04 23:47:08 +02:00
}
2020-05-01 14:02:23 +02:00
/// <summary>
/// Look at the specified location
/// </summary>
/// <param name="location">Location to look at</param>
protected void LookAtLocation ( Mapping . Location location )
{
Handler . UpdateLocation ( Handler . GetCurrentLocation ( ) , location ) ;
}
2014-07-20 12:02:17 +02:00
/// <summary>
2015-05-18 16:15:58 +02:00
/// Get a Y-M-D h:m:s timestamp representing the current system date and time
2014-07-20 12:02:17 +02:00
/// </summary>
2015-06-20 22:58:18 +02:00
protected static string GetTimestamp ( )
2014-07-20 12:02:17 +02:00
{
DateTime time = DateTime . Now ;
2015-05-18 16:15:58 +02:00
return String . Format ( "{0}-{1}-{2} {3}:{4}:{5}" ,
time . Year . ToString ( "0000" ) ,
time . Month . ToString ( "00" ) ,
time . Day . ToString ( "00" ) ,
time . Hour . ToString ( "00" ) ,
time . Minute . ToString ( "00" ) ,
time . Second . ToString ( "00" ) ) ;
2014-07-20 12:02:17 +02:00
}
2015-05-26 19:16:50 +02:00
/// <summary>
/// Load entries from a file as a string array, removing duplicates and empty lines
/// </summary>
/// <param name="file">File to load</param>
/// <returns>The string array or an empty array if failed to load the file</returns>
2015-06-21 16:40:13 +02:00
protected string [ ] LoadDistinctEntriesFromFile ( string file )
2015-05-26 19:16:50 +02:00
{
if ( File . Exists ( file ) )
{
//Read all lines from file, remove lines with no text, convert to lowercase,
//remove duplicate entries, convert to a string array, and return the result.
2020-05-29 20:23:03 +02:00
return File . ReadAllLines ( file , Encoding . UTF8 )
2015-05-26 19:16:50 +02:00
. Where ( line = > ! String . IsNullOrWhiteSpace ( line ) )
. Select ( line = > line . ToLower ( ) )
. Distinct ( ) . ToArray ( ) ;
}
else
{
2019-09-22 10:16:43 +02:00
LogToConsole ( "File not found: " + System . IO . Path . GetFullPath ( file ) ) ;
2015-05-26 19:16:50 +02:00
return new string [ 0 ] ;
}
}
2016-02-07 14:24:01 -08:00
2019-09-20 09:26:30 +02:00
/// <summary>
/// Return the Server Port where the client is connected to
/// </summary>
/// <returns>Server Port where the client is connected to</returns>
protected int GetServerPort ( )
{
return Handler . GetServerPort ( ) ;
}
/// <summary>
/// Return the Server Host where the client is connected to
/// </summary>
/// <returns>Server Host where the client is connected to</returns>
protected string GetServerHost ( )
{
return Handler . GetServerHost ( ) ;
}
/// <summary>
/// Return the Username of the current account
/// </summary>
/// <returns>Username of the current account</returns>
protected string GetUsername ( )
{
return Handler . GetUsername ( ) ;
}
2020-06-13 18:00:30 +05:00
/// <summary>
/// Return the Gamemode of the current account
/// </summary>
/// <returns>Username of the current account</returns>
protected int GetGamemode ( )
{
return Handler . GetGamemode ( ) ;
}
2019-09-20 09:26:30 +02:00
/// <summary>
/// Return the UserUUID of the current account
/// </summary>
/// <returns>UserUUID of the current account</returns>
protected string GetUserUUID ( )
{
return Handler . GetUserUUID ( ) ;
}
2016-10-14 21:14:26 +02:00
/// <summary>
/// Return the list of currently online players
/// </summary>
/// <returns>List of online players</returns>
protected string [ ] GetOnlinePlayers ( )
{
return Handler . GetOnlinePlayers ( ) ;
}
2019-03-30 10:47:59 -04:00
/// <summary>
/// Get a dictionary of online player names and their corresponding UUID
/// </summary>
/// <returns>
/// dictionary of online player whereby
/// UUID represents the key
/// playername represents the value</returns>
protected Dictionary < string , string > GetOnlinePlayersWithUUID ( )
{
return Handler . GetOnlinePlayersWithUUID ( ) ;
}
2016-02-07 14:24:01 -08:00
/// <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 ) ;
}
2020-03-23 19:59:00 +08:00
2020-04-08 18:23:19 +08:00
/// <summary>
/// Get server current TPS (tick per second)
/// </summary>
/// <returns>tps</returns>
2020-03-23 19:59:00 +08:00
protected Double GetServerTPS ( )
{
return Handler . GetServerTPS ( ) ;
}
/// <summary>
/// Interact with an entity
/// </summary>
/// <param name="EntityID"></param>
/// <param name="type">0: interact, 1: attack, 2: interact at</param>
2020-07-04 13:45:51 +05:00
/// <param name="hand">Hand.MainHand or Hand.OffHand</param>
2020-05-29 23:18:34 +05:00
/// <returns>TRUE in case of success</returns>
2020-07-04 13:45:51 +05:00
protected bool InteractEntity ( int EntityID , int type , Hand hand = Hand . MainHand )
2020-03-23 19:59:00 +08:00
{
2020-07-04 13:45:51 +05:00
return Handler . InteractEntity ( EntityID , type , hand ) ;
2020-03-23 19:59:00 +08:00
}
2020-03-27 21:14:05 +01:00
/// <summary>
2020-05-25 21:39:24 +02:00
/// Give Creative Mode items into regular/survival Player Inventory
2020-05-26 00:16:53 +05:00
/// </summary>
2020-05-25 21:39:24 +02:00
/// <remarks>(obviously) requires to be in creative mode</remarks>
2020-05-29 23:18:34 +05:00
/// </summary>
2020-05-25 21:39:24 +02:00
/// <param name="slot">Destination inventory slot</param>
/// <param name="itemType">Item type</param>
/// <param name="count">Item count</param>
/// <returns>TRUE if item given successfully</returns>
2020-06-20 21:30:23 +02:00
protected bool CreativeGive ( int slot , ItemType itemType , int count , Dictionary < string , object > nbt = null )
2020-05-26 00:16:53 +05:00
{
2020-06-20 21:30:23 +02:00
return Handler . DoCreativeGive ( slot , itemType , count , nbt ) ;
2020-05-26 00:16:53 +05:00
}
/// <summary>
2020-05-26 11:20:12 +02:00
/// Plays animation (Player arm swing)
2020-05-26 14:02:09 +05:00
/// </summary>
2020-07-04 13:45:51 +05:00
/// <param name="hand">Hand.MainHand or Hand.OffHand</param>
/// <returns>TRUE if animation successfully done</returns>
public bool SendAnimation ( Hand hand = Hand . MainHand )
2020-05-26 14:02:09 +05:00
{
2020-07-04 13:45:51 +05:00
return Handler . DoAnimation ( ( int ) hand ) ;
2020-05-26 14:02:09 +05:00
}
/// <summary>
2020-03-27 21:14:05 +01:00
/// Use item currently in the player's hand (active inventory bar slot)
/// </summary>
2020-05-29 23:18:34 +05:00
/// <returns>TRUE if successful</returns>
2020-05-03 10:48:02 -05:00
protected bool UseItemInHand ( )
2020-03-23 19:59:00 +08:00
{
return Handler . UseItemOnHand ( ) ;
}
2020-03-26 15:01:42 +08:00
2020-03-27 21:14:05 +01:00
/// <summary>
2020-05-26 11:20:12 +02:00
/// Check inventory handling enable status
/// </summary>
2020-05-29 23:18:34 +05:00
/// <returns>TRUE if inventory handling is enabled</returns>
2020-05-26 11:20:12 +02:00
public bool GetInventoryEnabled ( )
{
return Handler . GetInventoryEnabled ( ) ;
}
2020-05-29 23:18:34 +05:00
/// <summary>
2020-07-04 13:45:51 +05:00
/// Place the block at hand in the Minecraft world
2020-05-29 23:18:34 +05:00
/// </summary>
2020-07-04 13:45:51 +05:00
/// <param name="location">Location to place block to</param>
/// <param name="blockFace">Block face (e.g. Direction.Down when clicking on the block below to place this block)</param>
/// <param name="hand">Hand.MainHand or Hand.OffHand</param>
/// <returns>TRUE if successfully placed</returns>
public bool SendPlaceBlock ( Location location , Direction blockFace , Hand hand = Hand . MainHand )
2020-05-29 23:18:34 +05:00
{
2020-07-04 13:45:51 +05:00
return Handler . PlaceBlock ( location , blockFace , hand ) ;
2020-05-29 23:18:34 +05:00
}
2020-05-26 11:20:12 +02:00
/// <summary>
/// Get the player's inventory. Do not write to it, will not have any effect server-side.
2020-03-27 21:14:05 +01:00
/// </summary>
/// <returns>Player inventory</returns>
2020-03-26 15:01:42 +08:00
protected Container GetPlayerInventory ( )
{
Container container = Handler . GetPlayerInventory ( ) ;
2020-06-14 21:14:51 +08:00
return container = = null ? null : new Container ( container . ID , container . Type , container . Title , container . Items ) ;
2020-03-26 15:01:42 +08:00
}
2020-04-08 00:28:03 +08:00
/// <summary>
2020-05-26 11:20:12 +02:00
/// Get all inventories, player and container(s). Do not write to them. Will not have any effect server-side.
2020-04-08 00:28:03 +08:00
/// </summary>
2020-05-26 11:20:12 +02:00
/// <returns>All inventories</returns>
public Dictionary < int , Container > GetInventories ( )
{
return Handler . GetInventories ( ) ;
}
2020-05-29 23:18:34 +05:00
/// <summary>
/// Perform inventory action
/// </summary>
/// <param name="inventoryId">Inventory ID</param>
/// <param name="slot">Slot ID</param>
/// <param name="actionType">Action Type</param>
/// <returns>TRUE in case of success</returns>
protected bool WindowAction ( int inventoryId , int slot , WindowActionType actionType )
{
return Handler . DoWindowAction ( inventoryId , slot , actionType ) ;
}
2020-05-26 11:20:12 +02:00
/// <summary>
/// Change player selected hotbar slot
/// </summary>
/// <param name="slot">0-8</param>
2020-04-08 18:23:19 +08:00
/// <returns>True if success</returns>
protected bool ChangeSlot ( short slot )
2020-04-08 00:28:03 +08:00
{
2020-04-08 18:23:19 +08:00
return Handler . ChangeSlot ( slot ) ;
2020-04-08 00:28:03 +08:00
}
2020-04-11 14:33:22 +08:00
2020-05-26 11:20:12 +02:00
/// <summary>
/// Get current player selected hotbar slot
/// </summary>
/// <returns>0-8</returns>
2020-04-11 14:33:22 +08:00
protected byte GetCurrentSlot ( )
{
return Handler . GetCurrentSlot ( ) ;
}
2020-06-20 17:57:07 +05:00
/// <summary>
/// Clean all inventory
/// </summary>
/// <returns>TRUE if the uccessfully clear</returns>
protected bool ClearInventories ( )
{
return Handler . ClearInventories ( ) ;
}
/// <summary>
/// Update sign text
/// </summary>
/// <param name="location"> sign location</param>
/// <param name="line1"> text one</param>
/// <param name="line2"> text two</param>
/// <param name="line3"> text three</param>
/// <param name="line4"> text1 four</param>
protected bool UpdateSign ( Location location , string line1 , string line2 , string line3 , string line4 )
{
return Handler . UpdateSign ( location , line1 , line2 , line3 , line4 ) ;
}
2020-07-04 13:45:51 +05:00
/// <summary>
/// Update command block
/// </summary>
/// <param name="location">command block location</param>
/// <param name="command">command</param>
/// <param name="mode">command block mode</param>
/// <param name="flags">command block flags</param>
protected bool UpdateCommandBlock ( Location location , string command , CommandBlockMode mode , CommandBlockFlags flags )
{
return Handler . UpdateCommandBlock ( location , command , mode , flags ) ;
}
2020-07-02 13:18:20 +08:00
/// <summary>
/// Register a command in command prompt
/// </summary>
2020-07-04 11:12:23 +02:00
/// <param name="cmdName">Name of the command</param>
/// <param name="cmdDesc">Description/usage of the command</param>
/// <param name="callback">Method for handling the command</param>
2020-07-02 13:18:20 +08:00
/// <returns>True if successfully registered</returns>
2020-07-04 11:12:23 +02:00
protected bool RegisterChatBotCommand ( string cmdName , string cmdDesc , CommandRunner callback )
2020-07-02 13:18:20 +08:00
{
2020-07-04 11:12:23 +02:00
return Handler . RegisterCommand ( cmdName , cmdDesc , callback ) ;
2020-07-02 13:18:20 +08:00
}
2020-07-04 13:45:51 +05:00
/// <summary>
/// Command runner definition.
/// Returned string will be the output of the command
/// </summary>
/// <param name="command">Full command</param>
/// <param name="args">Arguments in the command</param>
2020-07-04 11:12:23 +02:00
/// <returns>Command result to display to the user</returns>
2020-07-04 13:45:51 +05:00
public delegate string CommandRunner ( string command , string [ ] args ) ;
2020-07-02 13:18:20 +08:00
/// <summary>
2020-07-04 13:45:51 +05:00
/// Command class with constructor for creating command for ChatBots.
2020-07-02 13:18:20 +08:00
/// </summary>
2020-07-04 13:45:51 +05:00
public class ChatBotCommand : Command
2020-07-02 13:18:20 +08:00
{
2020-07-04 13:45:51 +05:00
public CommandRunner Runner ;
2020-07-04 11:12:23 +02:00
private readonly string _cmdName ;
private readonly string _cmdDesc ;
public override string CMDName { get { return _cmdName ; } }
public override string CMDDesc { get { return _cmdDesc ; } }
2020-07-04 13:45:51 +05:00
public override string Run ( McClient handler , string command , Dictionary < string , object > localVars )
{
return this . Runner ( command , getArgs ( command ) ) ;
}
/// <summary>
2020-07-04 11:12:23 +02:00
/// ChatBotCommand Constructor
2020-07-04 13:45:51 +05:00
/// </summary>
/// <param name="CMDName">Name of the command</param>
/// <param name="CMDDesc">Description/usage of the command</param>
/// <param name="runner">Method for handling the command</param>
2020-07-04 11:12:23 +02:00
public ChatBotCommand ( string cmdName , string cmdDesc , CommandRunner callback )
2020-07-04 13:45:51 +05:00
{
2020-07-04 11:12:23 +02:00
this . _cmdName = cmdName ;
this . _cmdDesc = cmdDesc ;
this . Runner = callback ;
2020-07-04 13:45:51 +05:00
}
2020-07-02 13:18:20 +08:00
}
2014-05-31 01:59:03 +02:00
}
}