diff --git a/MinecraftClient/ChatBot.cs b/MinecraftClient/ChatBot.cs index 41e29bad..13832f04 100644 --- a/MinecraftClient/ChatBot.cs +++ b/MinecraftClient/ChatBot.cs @@ -212,6 +212,14 @@ namespace MinecraftClient /// Player UUID /// New Game Mode (0: Survival, 1: Creative, 2: Adventure, 3: Spectator). public virtual void OnGamemodeUpdate(string playername, Guid uuid, int gamemode) { } + + /// + /// Called when the Latency has been updated for a player + /// + /// Player Name + /// Player UUID + /// Latency. + public virtual void OnLatencyUpdate(string playername, Guid uuid, int latency) { } /* =================================================================== */ /* ToolBox - Methods below might be useful while creating your bot. */ diff --git a/MinecraftClient/McTcpClient.cs b/MinecraftClient/McTcpClient.cs index 44086df7..82e312bf 100644 --- a/MinecraftClient/McTcpClient.cs +++ b/MinecraftClient/McTcpClient.cs @@ -1635,7 +1635,23 @@ namespace MinecraftClient foreach (ChatBot bot in bots.ToArray()) bot.OnExplosion(location, strength, affectedBlocks); } - + + /// + /// Called when Latency is updated + /// + /// player uuid + /// Latency + public void OnLatencyUpdate(Guid uuid, int latency) + { + string playerName = null; + if (onlinePlayers.ContainsKey(uuid)) + { + playerName = onlinePlayers[uuid]; + foreach (ChatBot bot in bots.ToArray()) + bot.OnLatencyUpdate(playerName, uuid, latency); + } + } + /// /// Called when Experience bar is updated /// diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 8f129203..0b30cef4 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -448,7 +448,8 @@ namespace MinecraftClient.Protocol.Handlers handler.OnGamemodeUpdate(uuid, gamemode); break; case 0x02: //Update latency - dataTypes.ReadNextVarInt(packetData); + int latency = dataTypes.ReadNextVarInt(packetData); + handler.OnLatencyUpdate(uuid, latency); //Update latency; break; case 0x03: //Update display name if (dataTypes.ReadNextBool(packetData)) @@ -1390,6 +1391,8 @@ namespace MinecraftClient.Protocol.Handlers Container inventory = handler.GetInventory(windowId); if (inventory.Items.ContainsKey(slotId)) inventory.Items[slotId].Count--; // server won't update us after dropped + if (inventory.Items[slotId].Count == 0) + inventory.Items.Remove(slotId); break; case WindowActionType.DropItemStack: button = 1; diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs index 34b3c916..d04f9fd4 100644 --- a/MinecraftClient/Protocol/IMinecraftComHandler.cs +++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs @@ -222,7 +222,14 @@ namespace MinecraftClient.Protocol /// Affected player's UUID /// New game mode void OnGamemodeUpdate(Guid uuid, int gamemode); - + + /// + /// Called when a player's latency has changed + /// + /// Affected player's UUID + /// latency + void OnLatencyUpdate(Guid uuid, int latency); + /// /// Called when Experience bar is updated /// diff --git a/MinecraftClient/WinAPI/ConsoleIcon.cs b/MinecraftClient/WinAPI/ConsoleIcon.cs index a320580c..c18ab21c 100644 --- a/MinecraftClient/WinAPI/ConsoleIcon.cs +++ b/MinecraftClient/WinAPI/ConsoleIcon.cs @@ -21,6 +21,32 @@ namespace MinecraftClient.WinAPI [DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetConsoleIcon(IntPtr hIcon); + /// + /// Asynchronously download the player's skin and set the head as console icon + /// + public enum WinMessages : uint + { + /// + /// An application sends the WM_SETICON message to associate a new large or small icon with a window. + /// The system displays the large icon in the ALT+TAB dialog box, and the small icon in the window caption. + /// + SETICON = 0x0080, + } + + [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] + private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam); + + + private static void SetWindowIcon(System.Drawing.Icon icon) + { + IntPtr mwHandle = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle; + IntPtr result01 = SendMessage(mwHandle, (int)WinMessages.SETICON, 0, icon.Handle); + IntPtr result02 = SendMessage(mwHandle, (int)WinMessages.SETICON, 1, icon.Handle); + } + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool SetConsoleIcon(IntPtr hIcon); + /// /// Asynchronously download the player's skin and set the head as console icon /// @@ -31,7 +57,7 @@ namespace MinecraftClient.WinAPI { Thread t = new Thread(new ThreadStart(delegate { - HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create("http://skins.minecraft.net/MinecraftSkins/" + playerName + ".png"); + HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create("https://minotar.net/helm/" + playerName + "/100.png"); try { using (HttpWebResponse httpWebReponse = (HttpWebResponse)httpWebRequest.GetResponse()) @@ -40,6 +66,7 @@ namespace MinecraftClient.WinAPI { Bitmap skin = new Bitmap(Image.FromStream(httpWebReponse.GetResponseStream())); //Read skin from network skin = skin.Clone(new Rectangle(8, 8, 8, 8), skin.PixelFormat); //Crop skin + SetWindowIcon(Icon.FromHandle(skin.GetHicon())); SetConsoleIcon(skin.GetHicon()); //Set skin as icon } catch (ArgumentException) { /* Invalid image in HTTP response */ }