Improve logging, auto respawn

See discussion in GitHub issue #918
This commit is contained in:
ORelio 2020-04-01 21:15:35 +02:00
parent e93f03bd4e
commit b01c50b792
7 changed files with 217 additions and 26 deletions

2
.gitignore vendored
View file

@ -1,3 +1,5 @@
/DebugTools/MinecraftClientProxy.suo
/DebugTools/MinecraftClientProxy.v11.suo
/MinecraftClient.v11.suo
/MinecraftClient.suo
/MinecraftClientGUI.v11.suo

View file

@ -24,8 +24,8 @@ namespace MinecraftClient.ChatBots
{
if (!GetEntityHandlingEnabled())
{
ConsoleIO.WriteLine("[AutoAttack] Entity Handling is not enabled in the config file!");
ConsoleIO.WriteLine("[AutoAttack] This bot will be unloaded.");
LogToConsole("Entity Handling is not enabled in the config file!");
LogToConsole("This bot will be unloaded.");
UnloadBot();
}
}

View file

@ -26,8 +26,8 @@ namespace MinecraftClient.ChatBots
{
if (!GetEntityHandlingEnabled())
{
ConsoleIO.WriteLine("[AutoFishing] Entity Handling is not enabled in the config file!");
ConsoleIO.WriteLine("[AutoFishing] This bot will be unloaded.");
LogToConsole("Entity Handling is not enabled in the config file!");
LogToConsole("This bot will be unloaded.");
UnloadBot();
}
inventoryEnabled = GetInventoryEnabled();
@ -39,7 +39,7 @@ namespace MinecraftClient.ChatBots
{
if (GetCurrentLocation().Distance(entity.Location) < 2 && !isFishing)
{
ConsoleIO.WriteLine("Threw a fishing rod");
LogToConsole("Threw a fishing rod");
fishingRod = entity;
LastPos = entity.Location;
isFishing = true;
@ -93,14 +93,14 @@ namespace MinecraftClient.ChatBots
/// </summary>
public void OnCaughtFish()
{
ConsoleIO.WriteLine(GetTimestamp()+": Caught a fish!");
LogToConsole(GetTimestamp() + ": Caught a fish!");
// retract fishing rod
UseItemOnHand();
if (inventoryEnabled)
{
if (!hasFishingRod())
{
ConsoleIO.WriteLine(GetTimestamp() + ": No Fishing Rod on hand. Maybe broken?");
LogToConsole(GetTimestamp() + ": No Fishing Rod on hand. Maybe broken?");
return;
}
}

View file

@ -384,8 +384,11 @@ namespace MinecraftClient
/// Write a prefixed log line. Prefix is set in LogPrefix.
/// </summary>
/// <param name="text">Text of the log line</param>
public static void WriteLogLine(string text)
/// <param name="acceptnewlines">Allow line breaks</param>
public static void WriteLogLine(string text, bool acceptnewlines = true)
{
if (!acceptnewlines)
text = text.Replace('\n', ' ');
WriteLineFormatted(LogPrefix + text);
}

View file

@ -11,7 +11,6 @@ using MinecraftClient.Proxy;
using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Mapping;
using MinecraftClient.Inventory;
using System.Threading.Tasks;
namespace MinecraftClient
{
@ -56,6 +55,7 @@ namespace MinecraftClient
private string sessionid;
private DateTime lastKeepAlive;
private object lastKeepAliveLock = new object();
private int respawnTicks = 0;
private int playerEntityID;
// not really understand the Inventory Class
@ -279,7 +279,7 @@ namespace MinecraftClient
}
else if (response_msg.Length > 0)
{
ConsoleIO.WriteLineFormatted("§8MCC: " + response_msg);
ConsoleIO.WriteLogLine(response_msg);
}
}
else SendText(text);
@ -342,7 +342,7 @@ namespace MinecraftClient
}
catch (Exception e)
{
ConsoleIO.WriteLine(e.Message);
ConsoleIO.WriteLogLine(e.Message);
}
}
}
@ -756,7 +756,7 @@ namespace MinecraftClient
ConsoleIO.WriteLineFormatted(text, true);
if (Settings.DisplayChatLinks)
foreach (string link in links)
ConsoleIO.WriteLineFormatted("§8MCC: Link: " + link, false);
ConsoleIO.WriteLogLine("Link: " + link, false);
foreach (ChatBot bot in bots.ToArray())
{
try
@ -769,7 +769,7 @@ namespace MinecraftClient
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLineFormatted("§8GetText: Got error from " + bot.ToString() + ": " + e.ToString());
ConsoleIO.WriteLogLine("GetText: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
@ -904,7 +904,7 @@ namespace MinecraftClient
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLineFormatted("§8Update: Got error from " + bot.ToString() + ": " + e.ToString());
ConsoleIO.WriteLogLine("Update: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
@ -941,6 +941,13 @@ namespace MinecraftClient
pitch = null;
}
}
if (Settings.AutoRespawn && respawnTicks > 0)
{
respawnTicks--;
if (respawnTicks == 0)
SendRespawnPacket();
}
}
/// <summary>
@ -1361,7 +1368,8 @@ namespace MinecraftClient
public bool PlaceBlock(Location location)
{
//WORK IN PROGRESS. MAY NOT WORK YET
ConsoleIO.WriteLine(location.ToString());
if (Settings.DebugMessages)
ConsoleIO.WriteLogLine(location.ToString());
return handler.SendPlayerBlockPlacement(0, location, 1, 0.5f, 0.5f, 0.5f, false);
}
@ -1388,18 +1396,16 @@ namespace MinecraftClient
/// <param name="health">Player current health</param>
public void OnUpdateHealth(float health)
{
if (Settings.AutoRespawn)
if (health <= 0)
{
if (health <= 0)
if (Settings.AutoRespawn)
{
ConsoleIO.WriteLine("Client player dead.");
ConsoleIO.WriteLine("Respawn after 1 second...");
Task.Factory.StartNew(delegate
{
// wait before respawn
Thread.Sleep(1000);
SendRespawnPacket();
});
ConsoleIO.WriteLogLine("You are dead. Automatically respawning after 1 second.");
respawnTicks = 10;
}
else
{
ConsoleIO.WriteLogLine("You are dead. Type /respawn to respawn.");
}
}
}

View file

@ -41,6 +41,18 @@ namespace MinecraftClient.Protocol.Handlers
ConsoleIO.WriteLineFormatted("§8Terrain & Movements currently not handled for that MC version.");
Handler.SetTerrainEnabled(false);
}
if (handler.GetInventoryEnabled())
{
ConsoleIO.WriteLineFormatted("§8Inventories are currently not handled for that MC version.");
handler.SetInventoryEnabled(false);
}
if (handler.GetEntityHandlingEnabled())
{
ConsoleIO.WriteLineFormatted("§8Entities are currently not handled for that MC version.");
handler.SetEntityHandlingEnabled(false);
}
}
private Protocol16Handler(TcpClient Client)
@ -155,7 +167,7 @@ namespace MinecraftClient.Protocol.Handlers
case 0x84: readData(11); nbr = readNextShort(); if (nbr > 0) { readData(nbr); } break;
case 0x85: if (protocolversion >= 74) { readData(13); } break;
case 0xC8:
if (readNextInt() == 2022) { ConsoleIO.WriteLineFormatted("§MCC: You are dead. Type /reco to respawn & reconnect."); }
if (readNextInt() == 2022) { ConsoleIO.WriteLogLine("You are dead. Type /respawn to respawn."); }
if (protocolversion >= 72) { readData(4); } else readData(1);
break;
case 0xC9:

View file

@ -0,0 +1,168 @@
//MCCScript 1.0
//using System.Threading.Tasks;
//==== CONFIG START ====
string vkToken = "";
string chatId = "";
string botCommunityId = "";
//==== CONFIG END ====
MCC.LoadBot(new VkMessager(vkToken, chatId, botCommunityId));
//MCCScript Extensions
/// <summary>
/// This bot forwarding messages between Minecraft and VKonrakte chats.
/// Shares only messages that starts with dot ("."). Example: .Hello!
/// Also, send message to VK when any player joins or leaves.
///
/// Needs:
/// - VK Community token (also LongPool API with NewMessageEvent, api >= 5.80),
/// - VK ChatId (typically 2000000001, etc.)
/// - Bot's CommunityId
/// </summary>
public class VkMessager : ChatBot
{
private VkLongPoolClient VkLongPoolClient { get; set; }
private readonly string ChatId;
/// <summary>
/// This bot forwarding messages between Minecraft and VKonrakte chats.
/// Shares only messages that starts with dot ("."). Example: .Hello!
/// Also, send message to VK when any player joins or leaves.
/// </summary>
/// <param name="vkToken">VK Community token</param>
/// <param name="chatId">VK ChatId</param>
/// <param name="botCommunityId">Bot's CommunityId</param>
public VkMessager(string vkToken, string chatId, string botCommunityId)
{
VkLongPoolClient = new VkLongPoolClient(vkToken, botCommunityId, ProcessMsgFromVk);
ChatId = chatId;
}
public override void GetText(string text)
{
text = GetVerbatim(text);
string sender = "";
string message = "";
if (IsChatMessage(text, ref message, ref sender))
{
ProcessMsgFromMinecraft(sender, message);
}
else if (IsPrivateMessage(text, ref message, ref sender))
{
ProcessMsgFromMinecraft(sender, message);
}
else
{
ProcessMsgFromMinecraft("Server", text);
}
}
private void ProcessMsgFromVk(string senderId, string text)
{
if (!text.StartsWith(".")) return;
SendText("[VK " + senderId.Substring(0, 2) + "]: " + text.TrimStart('.'));
}
private void ProcessMsgFromMinecraft(string senderName, string text)
{
if (!text.StartsWith(".") && !text.Contains("left") && !text.Contains("joined")) return;
if (text.Contains("[VK")) return; // loop protection
VkLongPoolClient.SendMessage(ChatId, String.Format("[MC {0}]\r\n{1}", senderName, text.TrimStart('.')));
}
}
/// <summary>
/// Client for VK Community (bot) LongPool API.
/// Also can send messages.
/// </summary>
internal class VkLongPoolClient
{
public VkLongPoolClient(string token, string botCommunityId, Action<string, string> onMessageReceivedCallback, IWebProxy webProxy = null)
{
Token = token;
BotCommunityId = botCommunityId;
OnMessageReceivedCallback = onMessageReceivedCallback;
ReceiverWebClient = new WebClient() { Proxy = webProxy, Encoding = Encoding.UTF8 };
SenderWebClient = new WebClient() { Proxy = webProxy, Encoding = Encoding.UTF8 };
Init();
StartLongPoolAsync();
}
private WebClient ReceiverWebClient { get; set; }
private WebClient SenderWebClient { get; set; }
private string Token { get; set; }
private string LastTs { get; set; }
private string Server { get; set; }
private string Key { get; set; }
private Action<string, string> OnMessageReceivedCallback { get; set; }
private string BotCommunityId { get; set; }
private void Init()
{
var jsonResult = CallVkMethod("groups.getLongPollServer", "group_id=" + BotCommunityId);
var data = Json.ParseJson(jsonResult);
Key = data.Properties["response"].Properties["key"].StringValue;
Server = data.Properties["response"].Properties["server"].StringValue;
LastTs = data.Properties["response"].Properties["ts"].StringValue;
}
public void SendMessage(string chatId, string text)
{
CallVkMethod("messages.send", "peer_id=" + chatId + "&message=" + text);
}
private void StartLongPoolAsync()
{
var baseUrl = String.Format("{0}?act=a_check&version=2&wait=25&key={1}&ts=", Server, Key);
Task.Factory.StartNew(() =>
{
while (true)
{
var data = ReceiverWebClient.DownloadString(baseUrl + LastTs);
var messages = ProcessResponse(data);
foreach (var message in messages)
{
OnMessageReceivedCallback(message.Item1, message.Item2);
}
}
});
}
private IEnumerable<Tuple<string, string>> ProcessResponse(string jsonData)
{
var data = Json.ParseJson(jsonData);
LastTs = data.Properties["ts"].StringValue;
var updates = data.Properties["updates"].DataArray;
var messages = new List<Tuple<string, string>>();
foreach (var str in updates)
{
if (str.Properties["type"].StringValue != "message_new") continue;
var msgData = str.Properties["object"].Properties;
var userId = msgData["from_id"].StringValue;
var msgText = msgData["text"].StringValue;
messages.Add(new Tuple<string, string>(userId, msgText));
}
return messages;
}
private string CallVkMethod(string methodName, string data)
{
var url = String.Format("https://api.vk.com/method/{0}?v=5.80&access_token={1}&{2}", methodName, Token, data);
var jsonResult = SenderWebClient.DownloadString(url);
return jsonResult;
}
}