Re-added WebSocketChat bot and improved it, no longer using WebsocketSharp library

This commit is contained in:
Anon 2023-05-27 19:46:28 +02:00
parent 9855e2e0f1
commit 1efa55206f
9 changed files with 1642 additions and 25 deletions

File diff suppressed because it is too large Load diff

View file

@ -25,12 +25,24 @@ namespace MinecraftClient
/// </summary>
public class JSONData
{
public enum DataType { Object, Array, String };
public enum DataType
{
Object,
Array,
String
};
private readonly DataType type;
public DataType Type { get { return type; } }
public DataType Type
{
get { return type; }
}
public Dictionary<string, JSONData> Properties;
public List<JSONData> DataArray;
public string StringValue;
public JSONData(DataType datatype)
{
type = datatype;
@ -63,12 +75,21 @@ namespace MinecraftClient
if (toparse[cursorpos] == '"')
{
JSONData propertyname = String2Data(toparse, ref cursorpos);
if (toparse[cursorpos] == ':') { cursorpos++; } else { /* parse error ? */ }
if (toparse[cursorpos] == ':')
{
cursorpos++;
}
else
{
/* parse error ? */
}
JSONData propertyData = String2Data(toparse, ref cursorpos);
data.Properties[propertyname.StringValue] = propertyData;
}
else cursorpos++;
}
cursorpos++;
break;
@ -79,10 +100,15 @@ namespace MinecraftClient
SkipSpaces(toparse, ref cursorpos);
while (toparse[cursorpos] != ']')
{
if (toparse[cursorpos] == ',') { cursorpos++; }
if (toparse[cursorpos] == ',')
{
cursorpos++;
}
JSONData arrayItem = String2Data(toparse, ref cursorpos);
data.DataArray.Add(arrayItem);
}
cursorpos++;
break;
@ -103,9 +129,11 @@ namespace MinecraftClient
&& IsHex(toparse[cursorpos + 5]))
{
//"abc\u0123abc" => "0123" => 0123 => Unicode char n°0123 => Add char to string
data.StringValue += char.ConvertFromUtf32(int.Parse(toparse.Substring(cursorpos + 2, 4),
data.StringValue += char.ConvertFromUtf32(int.Parse(
toparse.Substring(cursorpos + 2, 4),
System.Globalization.NumberStyles.HexNumber));
cursorpos += 6; continue;
cursorpos += 6;
continue;
}
else if (toparse[cursorpos + 1] == 'n')
{
@ -127,12 +155,20 @@ namespace MinecraftClient
}
else cursorpos++; //Normal character escapement \"
}
catch (IndexOutOfRangeException) { cursorpos++; } // \u01<end of string>
catch (ArgumentOutOfRangeException) { cursorpos++; } // Unicode index 0123 was invalid
catch (IndexOutOfRangeException)
{
cursorpos++;
} // \u01<end of string>
catch (ArgumentOutOfRangeException)
{
cursorpos++;
} // Unicode index 0123 was invalid
}
data.StringValue += toparse[cursorpos];
cursorpos++;
}
cursorpos++;
break;
@ -151,11 +187,13 @@ namespace MinecraftClient
case '-':
data = new JSONData(JSONData.DataType.String);
StringBuilder sb = new();
while ((toparse[cursorpos] >= '0' && toparse[cursorpos] <= '9') || toparse[cursorpos] == '.' || toparse[cursorpos] == '-')
while ((toparse[cursorpos] >= '0' && toparse[cursorpos] <= '9') || toparse[cursorpos] == '.' ||
toparse[cursorpos] == '-')
{
sb.Append(toparse[cursorpos]);
cursorpos++;
}
data.StringValue = sb.ToString();
break;
@ -163,28 +201,71 @@ namespace MinecraftClient
case 't':
data = new JSONData(JSONData.DataType.String);
cursorpos++;
if (toparse[cursorpos] == 'r') { cursorpos++; }
if (toparse[cursorpos] == 'u') { cursorpos++; }
if (toparse[cursorpos] == 'e') { cursorpos++; data.StringValue = "true"; }
if (toparse[cursorpos] == 'r')
{
cursorpos++;
}
if (toparse[cursorpos] == 'u')
{
cursorpos++;
}
if (toparse[cursorpos] == 'e')
{
cursorpos++;
data.StringValue = "true";
}
break;
//Boolean : false
case 'f':
data = new JSONData(JSONData.DataType.String);
cursorpos++;
if (toparse[cursorpos] == 'a') { cursorpos++; }
if (toparse[cursorpos] == 'l') { cursorpos++; }
if (toparse[cursorpos] == 's') { cursorpos++; }
if (toparse[cursorpos] == 'e') { cursorpos++; data.StringValue = "false"; }
if (toparse[cursorpos] == 'a')
{
cursorpos++;
}
if (toparse[cursorpos] == 'l')
{
cursorpos++;
}
if (toparse[cursorpos] == 's')
{
cursorpos++;
}
if (toparse[cursorpos] == 'e')
{
cursorpos++;
data.StringValue = "false";
}
break;
//Null field
case 'n':
data = new JSONData(JSONData.DataType.String);
cursorpos++;
if (toparse[cursorpos] == 'u') { cursorpos++; }
if (toparse[cursorpos] == 'l') { cursorpos++; }
if (toparse[cursorpos] == 'l') { cursorpos++; data.StringValue = "null"; }
if (toparse[cursorpos] == 'u')
{
cursorpos++;
}
if (toparse[cursorpos] == 'l')
{
cursorpos++;
}
if (toparse[cursorpos] == 'l')
{
cursorpos++;
data.StringValue = "null";
}
break;
//Unknown data
@ -192,6 +273,7 @@ namespace MinecraftClient
cursorpos++;
return String2Data(toparse, ref cursorpos);
}
SkipSpaces(toparse, ref cursorpos);
return data;
}
@ -206,7 +288,10 @@ namespace MinecraftClient
/// </summary>
/// <param name="c">Char to test</param>
/// <returns>True if hexadecimal</returns>
private static bool IsHex(char c) { return ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')); }
private static bool IsHex(char c)
{
return ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'));
}
/// <summary>
/// Advance the cursor to skip white spaces and line breaks
@ -216,10 +301,77 @@ namespace MinecraftClient
private static void SkipSpaces(string toparse, ref int cursorpos)
{
while (cursorpos < toparse.Length
&& (char.IsWhiteSpace(toparse[cursorpos])
|| toparse[cursorpos] == '\r'
|| toparse[cursorpos] == '\n'))
&& (char.IsWhiteSpace(toparse[cursorpos])
|| toparse[cursorpos] == '\r'
|| toparse[cursorpos] == '\n'))
cursorpos++;
}
// Original: https://github.com/mono/mono/blob/master/mcs/class/System.Json/System.Json/JsonValue.cs
private static bool NeedEscape(string src, int i)
{
var c = src[i];
return c < 32 || c == '"' || c == '\\'
// Broken lead surrogate
|| (c is >= '\uD800' and <= '\uDBFF' &&
(i == src.Length - 1 || src[i + 1] < '\uDC00' || src[i + 1] > '\uDFFF'))
// Broken tail surrogate
|| (c is >= '\uDC00' and <= '\uDFFF' &&
(i == 0 || src[i - 1] < '\uD800' || src[i - 1] > '\uDBFF'))
// To produce valid JavaScript
|| c == '\u2028' || c == '\u2029'
// Escape "</" for <script> tags
|| (c == '/' && i > 0 && src[i - 1] == '<');
}
public static string EscapeString(string src)
{
var sb = new StringBuilder();
var start = 0;
for (var i = 0; i < src.Length; i++)
{
if (!NeedEscape(src, i)) continue;
sb.Append(src, start, i - start);
switch (src[i])
{
case '\b':
sb.Append("\\b");
break;
case '\f':
sb.Append("\\f");
break;
case '\n':
sb.Append("\\n");
break;
case '\r':
sb.Append("\\r");
break;
case '\t':
sb.Append("\\t");
break;
case '\"':
sb.Append("\\\"");
break;
case '\\':
sb.Append("\\\\");
break;
case '/':
sb.Append("\\/");
break;
default:
sb.Append("\\u");
sb.Append(((int)src[i]).ToString("x04"));
break;
}
start = i + 1;
}
sb.Append(src, start, src.Length - start);
return sb.ToString();
}
}
}
}

View file

@ -297,6 +297,7 @@ namespace MinecraftClient
if (Config.ChatBot.ScriptScheduler.Enabled) { BotLoad(new ScriptScheduler()); }
if (Config.ChatBot.TelegramBridge.Enabled) { BotLoad(new TelegramBridge()); }
if (Config.ChatBot.ItemsCollector.Enabled) { BotLoad(new ItemsCollector()); }
if (Config.ChatBot.WebSocketBot.Enabled) { BotLoad(new WebSocketBot()); }
//Add your ChatBot here by uncommenting and adapting
//BotLoad(new ChatBots.YourBot());
}

View file

@ -1238,5 +1238,35 @@ namespace MinecraftClient {
return ResourceManager.GetString("ChatBot.ItemsCollector", resourceCulture);
}
}
internal static string ChatBot_WebSocketBot {
get {
return ResourceManager.GetString("ChatBot.WebSocketBot", resourceCulture);
}
}
internal static string ChatBot_WebSocketBot_Ip {
get {
return ResourceManager.GetString("ChatBot.WebSocketBot.Ip", resourceCulture);
}
}
internal static string ChatBot_WebSocketBot_Port {
get {
return ResourceManager.GetString("ChatBot.WebSocketBot.Port", resourceCulture);
}
}
internal static string ChatBot_WebSocketBot_Password {
get {
return ResourceManager.GetString("ChatBot.WebSocketBot.Password", resourceCulture);
}
}
internal static string ChatBot_WebSocketBot_DebugMode {
get {
return ResourceManager.GetString("ChatBot.WebSocketBot.DebugMode", resourceCulture);
}
}
}
}

View file

@ -828,4 +828,19 @@ If the connection to the Minecraft game server is blocked by the firewall, set E
<data name="ChatBot.ItemsCollector" xml:space="preserve">
<value>A Chat Bot that collects items on the ground</value>
</data>
<data name="ChatBot.WebSocketBot" xml:space="preserve">
<value>Remotely control the client using Web Sockets.\n# This is useful if you want to implement an application that can remotely and asynchronously execute procedures in MCC.\n# Example implementation written in JavaScript: https://github.com/milutinke/MCC.js.git\n# The protocol specification will be available in the documentation soon.</value>
</data>
<data name="ChatBot.WebSocketBot.Ip" xml:space="preserve">
<value>The IP address that Websocket server will be bound to.</value>
</data>
<data name="ChatBot.WebSocketBot.Port" xml:space="preserve">
<value>The Port that Websocket server will be bounded to.</value>
</data>
<data name="ChatBot.WebSocketBot.Password" xml:space="preserve">
<value>A password that will be used to authenticate on thw Websocket server (It is recommended to change the default password and to set a strong one).</value>
</data>
<data name="ChatBot.WebSocketBot.DebugMode" xml:space="preserve">
<value>This setting is for developers who are developing a library that uses this chat bot to remotely execute procedures/commands/functions.</value>
</data>
</root>

View file

@ -3854,5 +3854,71 @@ namespace MinecraftClient {
return ResourceManager.GetString("cmd.items.collector.stopped", resourceCulture);
}
}
internal static string bot_WebSocketBot_failed_to_start_ip {
get {
return ResourceManager.GetString("bot.WebSocketBot.failed_to_start.ip", resourceCulture);
}
}
internal static string bot_WebSocketBot_failed_to_start_port {
get {
return ResourceManager.GetString("bot.WebSocketBot.failed_to_start.port", resourceCulture);
}
}
internal static string ChatBot_WebSocketBot_DebugMode {
get {
return ResourceManager.GetString("ChatBot.WebSocketBot.DebugMode", resourceCulture);
}
}
internal static string bot_WebSocketBot_starting {
get {
return ResourceManager.GetString("bot.WebSocketBot.starting", resourceCulture);
}
}
internal static string bot_WebSocketBot_started {
get {
return ResourceManager.GetString("bot.WebSocketBot.started", resourceCulture);
}
}
internal static string bot_WebSocketBot_failed_to_start_custom {
get {
return ResourceManager.GetString("bot.WebSocketBot.failed_to_start.custom", resourceCulture);
}
}
internal static string bot_WebSocketBot_new_session {
get {
return ResourceManager.GetString("bot.WebSocketBot.new_session", resourceCulture);
}
}
internal static string bot_WebSocketBot_session_disconnected {
get {
return ResourceManager.GetString("bot.WebSocketBot.session_disconnected", resourceCulture);
}
}
internal static string bot_WebSocketBot_session_id_changed {
get {
return ResourceManager.GetString("bot.WebSocketBot.session_id_changed", resourceCulture);
}
}
internal static string bot_WebSocketBot_session_id_failed_to_change {
get {
return ResourceManager.GetString("bot.WebSocketBot.session_id_failed_to_change", resourceCulture);
}
}
internal static string bot_WebSocketBot_session_authenticated {
get {
return ResourceManager.GetString("bot.WebSocketBot.session_authenticated", resourceCulture);
}
}
}
}

View file

@ -2058,4 +2058,37 @@ Logging in...</value>
<data name="cmd.items.collector.stopped" xml:space="preserve">
<value>Stopped collecting items.</value>
</data>
<data name="bot.WebSocketBot.failed_to_start.ip" xml:space="preserve">
<value>§cFailed to start a server! The provided IP address is not a valid one!</value>
</data>
<data name="bot.WebSocketBot.failed_to_start.port" xml:space="preserve">
<value>§cFailed to start a server! The provided port number {0} is out of the range, it must be 65535 or bellow it!</value>
</data>
<data name="ChatBot.WebSocketBot.DebugMode" xml:space="preserve">
<value />
</data>
<data name="bot.WebSocketBot.starting" xml:space="preserve">
<value>Starting the Websocket server...</value>
</data>
<data name="bot.WebSocketBot.started" xml:space="preserve">
<value>§bServer started on ip §a{0}§b port: §a{1}</value>
</data>
<data name="bot.WebSocketBot.failed_to_start.custom" xml:space="preserve">
<value>§cFailed to start a server:\n\n{0}\n\n</value>
</data>
<data name="bot.WebSocketBot.new_session" xml:space="preserve">
<value>§bNew session connected: §a{0}</value>
</data>
<data name="bot.WebSocketBot.session_disconnected" xml:space="preserve">
<value>§bSession with an id §a{0}§b has disconnected!</value>
</data>
<data name="bot.WebSocketBot.session_id_changed" xml:space="preserve">
<value>§bSession with an id §a{0}§b has been renamed to: §a{1}§b!</value>
</data>
<data name="bot.WebSocketBot.session_id_failed_to_change" xml:space="preserve">
<value>§cSession with an id §a{0}§b failed to chage the ID to: §c{1}§b!</value>
</data>
<data name="bot.WebSocketBot.session_authenticated" xml:space="preserve">
<value>§bSession with an id §a{0}§b has been succesfully authenticated!</value>
</data>
</root>

View file

@ -1050,7 +1050,7 @@ namespace MinecraftClient.Scripting
/// <summary>
/// Send Entity Action
/// </summary>
private bool SendEntityAction(Protocol.EntityActionType entityAction)
protected bool SendEntityAction(Protocol.EntityActionType entityAction)
{
return Handler.SendEntityAction(entityAction);
}

View file

@ -1404,6 +1404,13 @@ namespace MinecraftClient
get { return ChatBots.ItemsCollector.Config; }
set { ChatBots.ItemsCollector.Config = value; ChatBots.ItemsCollector.Config.OnSettingUpdate(); }
}
[TomlPrecedingComment("$ChatBot.WebSocketBot$")]
public ChatBots.WebSocketBot.Configs WebSocketBot
{
get { return ChatBots.WebSocketBot.Config!; }
set { ChatBots.WebSocketBot.Config = value; }
}
}
}