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.v11.suo
/MinecraftClient.suo /MinecraftClient.suo
/MinecraftClientGUI.v11.suo /MinecraftClientGUI.v11.suo

View file

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

View file

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

View file

@ -384,8 +384,11 @@ namespace MinecraftClient
/// Write a prefixed log line. Prefix is set in LogPrefix. /// Write a prefixed log line. Prefix is set in LogPrefix.
/// </summary> /// </summary>
/// <param name="text">Text of the log line</param> /// <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); WriteLineFormatted(LogPrefix + text);
} }

View file

@ -11,7 +11,6 @@ using MinecraftClient.Proxy;
using MinecraftClient.Protocol.Handlers.Forge; using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using System.Threading.Tasks;
namespace MinecraftClient namespace MinecraftClient
{ {
@ -56,6 +55,7 @@ namespace MinecraftClient
private string sessionid; private string sessionid;
private DateTime lastKeepAlive; private DateTime lastKeepAlive;
private object lastKeepAliveLock = new object(); private object lastKeepAliveLock = new object();
private int respawnTicks = 0;
private int playerEntityID; private int playerEntityID;
// not really understand the Inventory Class // not really understand the Inventory Class
@ -279,7 +279,7 @@ namespace MinecraftClient
} }
else if (response_msg.Length > 0) else if (response_msg.Length > 0)
{ {
ConsoleIO.WriteLineFormatted("§8MCC: " + response_msg); ConsoleIO.WriteLogLine(response_msg);
} }
} }
else SendText(text); else SendText(text);
@ -342,7 +342,7 @@ namespace MinecraftClient
} }
catch (Exception e) catch (Exception e)
{ {
ConsoleIO.WriteLine(e.Message); ConsoleIO.WriteLogLine(e.Message);
} }
} }
} }
@ -756,7 +756,7 @@ namespace MinecraftClient
ConsoleIO.WriteLineFormatted(text, true); ConsoleIO.WriteLineFormatted(text, true);
if (Settings.DisplayChatLinks) if (Settings.DisplayChatLinks)
foreach (string link in links) foreach (string link in links)
ConsoleIO.WriteLineFormatted("§8MCC: Link: " + link, false); ConsoleIO.WriteLogLine("Link: " + link, false);
foreach (ChatBot bot in bots.ToArray()) foreach (ChatBot bot in bots.ToArray())
{ {
try try
@ -769,7 +769,7 @@ namespace MinecraftClient
{ {
if (!(e is ThreadAbortException)) 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 else throw; //ThreadAbortException should not be caught
} }
@ -904,7 +904,7 @@ namespace MinecraftClient
{ {
if (!(e is ThreadAbortException)) 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 else throw; //ThreadAbortException should not be caught
} }
@ -941,6 +941,13 @@ namespace MinecraftClient
pitch = null; pitch = null;
} }
} }
if (Settings.AutoRespawn && respawnTicks > 0)
{
respawnTicks--;
if (respawnTicks == 0)
SendRespawnPacket();
}
} }
/// <summary> /// <summary>
@ -1361,7 +1368,8 @@ namespace MinecraftClient
public bool PlaceBlock(Location location) public bool PlaceBlock(Location location)
{ {
//WORK IN PROGRESS. MAY NOT WORK YET //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); return handler.SendPlayerBlockPlacement(0, location, 1, 0.5f, 0.5f, 0.5f, false);
} }
@ -1387,19 +1395,17 @@ namespace MinecraftClient
/// </summary> /// </summary>
/// <param name="health">Player current health</param> /// <param name="health">Player current health</param>
public void OnUpdateHealth(float health) public void OnUpdateHealth(float health)
{
if (Settings.AutoRespawn)
{ {
if (health <= 0) if (health <= 0)
{ {
ConsoleIO.WriteLine("Client player dead."); if (Settings.AutoRespawn)
ConsoleIO.WriteLine("Respawn after 1 second...");
Task.Factory.StartNew(delegate
{ {
// wait before respawn ConsoleIO.WriteLogLine("You are dead. Automatically respawning after 1 second.");
Thread.Sleep(1000); respawnTicks = 10;
SendRespawnPacket(); }
}); 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."); ConsoleIO.WriteLineFormatted("§8Terrain & Movements currently not handled for that MC version.");
Handler.SetTerrainEnabled(false); 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) 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 0x84: readData(11); nbr = readNextShort(); if (nbr > 0) { readData(nbr); } break;
case 0x85: if (protocolversion >= 74) { readData(13); } break; case 0x85: if (protocolversion >= 74) { readData(13); } break;
case 0xC8: 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); if (protocolversion >= 72) { readData(4); } else readData(1);
break; break;
case 0xC9: 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;
}
}