From fb50b0d5cbe622e3d535b3a440ef5d6a65468cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D0=BE=D0=BC=D0=B0=20=D0=94=D0=B0=D0=BD=D0=B8=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= <35975332+Nekiplay@users.noreply.github.com> Date: Sat, 4 Jul 2020 13:45:51 +0500 Subject: [PATCH] ChatBot API: OnScoreboardObjective, OnEntityEffect, OnUpdateScore, EntityInteract, Hand list (#1097) * Create Effect.cs * Rename Effect.cs to Effects.cs * Update MinecraftClient.csproj * Update Effects.cs * Update Effects.cs * add EntityEffect * Update McClient.cs * Update Protocol18.cs + EntityEffect * Update IMinecraftComHandler.cs * Update Protocol18PacketTypes.cs + EntityEffect * Update ChatBot.cs + OnEntityEquipment * Update PacketIncomingType.cs + ScoreboardObjective * Update Protocol18PacketTypes.cs * Update Protocol18.cs * Update IMinecraftComHandler.cs + OnScoreboardObjective * Update McClient.cs + OnScoreboardObjective * Update ChatBot.cs + OnScoreboardObjective event * Update Protocol18.cs: fix scoreboard * Update McClient.cs * Update ChatBot.cs * Update PacketIncomingType.cs * Update ChatBot.cs + OnUpdateScore * Update McClient.cs + OnUpdateScore * Update IMinecraftComHandler.cs + OnUpdateScore * Update Protocol18.cs * Update Protocol18PacketTypes.cs * Update Protocol18.cs + fix micro lags * Update Protocol18.cs * Update Protocol18.cs * Update Protocol18.cs * Update Protocol16.cs * Update Protocol18.cs * Update McClient.cs * Update IMinecraftCom.cs * Update McClient.cs * Update McClient.cs * Update McClient.cs * Update ChatBot.cs + GetEntities() * Create Hand.cs * Update MinecraftClient.csproj * Update McClient.cs * Update ChatBot.cs * Update Protocol18.cs * Update ChatBot.cs * Update ChatBot.cs * Update ChatBot.cs * Update ChatBot.cs * Update ChatBot.cs: fix * Update AutoAttack.cs: Fix * Update McClient.cs: compile fix * Update ChatBot.cs * Update AutoAttack.cs * Update ChatBot.cs * Update Protocol18.cs * Update IMinecraftComHandler.cs * Update McClient.cs * Update ChatBot.cs * Update Protocol18.cs * Update IMinecraftComHandler.cs * Update ChatBot.cs * Update McClient.cs * Update McClient.cs: remove check distance * Update EntityActionType.cs: more actions * Create CommandBlockMode.cs * Create CommandBlockFlags.cs * Update IMinecraftCom.cs * Update McClient.cs * Update ChatBot.cs * Update Protocol18.cs * Update Protocol16.cs * Update PacketOutgoingType.cs * Update Protocol18PacketTypes.cs * Update Protocol18.cs --- MinecraftClient/ChatBot.cs | 140 ++++++++++++------ MinecraftClient/ChatBots/AutoAttack.cs | 2 +- MinecraftClient/Inventory/Effects.cs | 47 ++++++ MinecraftClient/Inventory/Hand.cs | 11 ++ MinecraftClient/Mapping/CommandBlockFlags.cs | 18 +++ MinecraftClient/Mapping/CommandBlockMode.cs | 18 +++ MinecraftClient/McClient.cs | 82 +++++++++- MinecraftClient/MinecraftClient.csproj | 4 +- MinecraftClient/Protocol/EntityActionType.cs | 18 ++- .../Protocol/Handlers/PacketIncomingType.cs | 5 +- .../Protocol/Handlers/PacketOutgoingType.cs | 1 + .../Protocol/Handlers/Protocol16.cs | 12 +- .../Protocol/Handlers/Protocol18.cs | 111 ++++++++++++-- .../Handlers/Protocol18PacketTypes.cs | 32 ++++ MinecraftClient/Protocol/IMinecraftCom.cs | 18 +++ .../Protocol/IMinecraftComHandler.cs | 28 ++++ 16 files changed, 469 insertions(+), 78 deletions(-) create mode 100644 MinecraftClient/Inventory/Effects.cs create mode 100644 MinecraftClient/Inventory/Hand.cs create mode 100644 MinecraftClient/Mapping/CommandBlockFlags.cs create mode 100644 MinecraftClient/Mapping/CommandBlockMode.cs diff --git a/MinecraftClient/ChatBot.cs b/MinecraftClient/ChatBot.cs index 69018281..d8bd0544 100644 --- a/MinecraftClient/ChatBot.cs +++ b/MinecraftClient/ChatBot.cs @@ -120,7 +120,7 @@ namespace MinecraftClient /// Text from the server /// Raw JSON from the server. This parameter will be NULL on MC 1.5 or lower! public virtual void GetText(string text, string json) { } - + /// /// Is called when the client has been disconnected fom the server /// @@ -250,6 +250,34 @@ namespace MinecraftClient /// Equipment slot. 0: main hand, 1: off hand, 2–5: armor slot (2: boots, 3: leggings, 4: chestplate, 5: helmet) /// Item) public virtual void OnEntityEquipment(Entity entity, int slot, Item item) { } + + /// + /// Called when the Entity use effects + /// + /// entity ID + /// effect id + /// effect amplifier + /// effect duration + /// effect flags + public virtual void OnEntityEffect(Entity entity, Effects effect, int amplifier, int duration, byte flags) { } + + /// + /// Called when coreboardObjective + /// + /// objective name + /// 0 to create the scoreboard. 1 to remove the scoreboard. 2 to update the display text. + /// Only if mode is 0 or 2. The text to be displayed for the score + /// Only if mode is 0 or 2. 0 = "integer", 1 = "hearts". + public virtual void OnScoreboardObjective(string objectivename, byte mode, string objectivevalue, int type, string json) { } + + /// + /// Called when DisplayScoreboard + /// + /// The entity whose score this is. For players, this is their username; for other entities, it is their UUID. + /// 0 to create/update an item. 1 to remove an item. + /// The name of the objective the score belongs to + /// he score to be displayed next to the entry. Only sent when Action does not equal 1. + public virtual void OnUpdateScore(string entityname, byte action, string objectivename, int value) { } /* =================================================================== */ /* ToolBox - Methods below might be useful while creating your bot. */ @@ -771,6 +799,15 @@ namespace MinecraftClient return Handler.GetWorld(); return null; } + + /// + /// Get all Entityes + /// + /// All Entities + protected Dictionary GetEntities() + { + return Handler.GetEntities(); + } /// /// Get the current location of the player @@ -960,10 +997,11 @@ namespace MinecraftClient /// /// /// 0: interact, 1: attack, 2: interact at + /// Hand.MainHand or Hand.OffHand /// TRUE in case of success - protected bool InteractEntity(int EntityID, int type) + protected bool InteractEntity(int EntityID, int type, Hand hand = Hand.MainHand) { - return Handler.InteractEntity(EntityID, type); + return Handler.InteractEntity(EntityID, type, hand); } /// @@ -983,11 +1021,11 @@ namespace MinecraftClient /// /// Plays animation (Player arm swing) /// - /// 0 for left arm, 1 for right arm - /// TRUE in case of success - protected bool SendAnimation(int animation) + /// Hand.MainHand or Hand.OffHand + /// TRUE if animation successfully done + public bool SendAnimation(Hand hand = Hand.MainHand) { - return Handler.DoAnimation(animation); + return Handler.DoAnimation((int)hand); } /// @@ -1009,13 +1047,15 @@ namespace MinecraftClient } /// - /// Place block + /// Place the block at hand in the Minecraft world /// - /// Block location - /// - protected bool SendPlaceBlock(Location location, Direction blockFace) + /// Location to place block to + /// Block face (e.g. Direction.Down when clicking on the block below to place this block) + /// Hand.MainHand or Hand.OffHand + /// TRUE if successfully placed + public bool SendPlaceBlock(Location location, Direction blockFace, Hand hand = Hand.MainHand) { - return Handler.PlaceBlock(location, blockFace); + return Handler.PlaceBlock(location, blockFace, hand); } /// @@ -1089,6 +1129,18 @@ namespace MinecraftClient { return Handler.UpdateSign(location, line1, line2, line3, line4); } + + /// + /// Update command block + /// + /// command block location + /// command + /// command block mode + /// command block flags + protected bool UpdateCommandBlock(Location location, string command, CommandBlockMode mode, CommandBlockFlags flags) + { + return Handler.UpdateCommandBlock(location, command, mode, flags); + } /// /// Register a command in command prompt @@ -1101,42 +1153,42 @@ namespace MinecraftClient { return Handler.RegisterCommand(CMDName, CMDDesc, Run); } - } - - /// - /// Command runner definition. - /// Returned string will be the output of the command - /// - /// Full command - /// Arguments in the command - /// - public delegate string CommandRunner(string command, string[] args); - - /// - /// Command class with constructor for creating command for ChatBots. - /// - public class ChatBotCommand : Command - { - public CommandRunner Runner; - - public override string CMDName { get; } - public override string CMDDesc { get; } - public override string Run(McClient handler, string command, Dictionary localVars) - { - return this.Runner(command, getArgs(command)); - } /// - /// Constructor + /// Command runner definition. + /// Returned string will be the output of the command /// - /// Name of the command - /// Description/usage of the command - /// Method for handling the command - public ChatBotCommand(string CMDName, string CMDDesc, CommandRunner runner) + /// Full command + /// Arguments in the command + /// + public delegate string CommandRunner(string command, string[] args); + + /// + /// Command class with constructor for creating command for ChatBots. + /// + public class ChatBotCommand : Command { - this.CMDName = CMDName; - this.CMDDesc = CMDDesc; - this.Runner = runner; + public CommandRunner Runner; + + public override string CMDName { get; } + public override string CMDDesc { get; } + public override string Run(McClient handler, string command, Dictionary localVars) + { + return this.Runner(command, getArgs(command)); + } + + /// + /// Constructor + /// + /// Name of the command + /// Description/usage of the command + /// Method for handling the command + public ChatBotCommand(string CMDName, string CMDDesc, CommandRunner runner) + { + this.CMDName = CMDName; + this.CMDDesc = CMDDesc; + this.Runner = runner; + } } } } diff --git a/MinecraftClient/ChatBots/AutoAttack.cs b/MinecraftClient/ChatBots/AutoAttack.cs index 4fcbda32..6ec12a0d 100644 --- a/MinecraftClient/ChatBots/AutoAttack.cs +++ b/MinecraftClient/ChatBots/AutoAttack.cs @@ -46,7 +46,7 @@ namespace MinecraftClient.ChatBots bool shouldAttack = handleEntity(entity.Value); if (shouldAttack) { - SendAnimation(0); // Hit Animation + SendAnimation(Inventory.Hand.MainHand); // Hit Animation InteractEntity(entity.Key, 1); // hit the entity! } } diff --git a/MinecraftClient/Inventory/Effects.cs b/MinecraftClient/Inventory/Effects.cs new file mode 100644 index 00000000..a5f3c194 --- /dev/null +++ b/MinecraftClient/Inventory/Effects.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MinecraftClient.Inventory +{ + /// + /// Represents a Minecraft effects + /// + public enum Effects + { + Speed = 1, + Slowness = 2, + Haste = 3, + MiningFatigue = 4, + Strength = 5, + InstantHealth = 6, + InstantDamage = 7, + JumpBoost = 8, + Nausea = 9, + Regeneration = 10, + Resistance = 11, + FireResistance = 12, + WaterBreathing = 13, + Invisibility = 14, + Blindness = 15, + NightVision = 16, + Hunger = 17, + Weakness = 18, + Poison = 19, + Wither = 20, + HealthBoost = 21, + Absorption = 22, + Saturation = 23, + Glowing = 24, + Levitation = 25, + Luck = 26, + BadLuck = 27, + SlowFalling = 28, + ConduitPower = 29, + DolphinsGrace = 30, + BadOmen = 31, + HerooftheVillage = 32, + } +} diff --git a/MinecraftClient/Inventory/Hand.cs b/MinecraftClient/Inventory/Hand.cs new file mode 100644 index 00000000..c78ded7f --- /dev/null +++ b/MinecraftClient/Inventory/Hand.cs @@ -0,0 +1,11 @@ +namespace MinecraftClient.Inventory +{ + /// + /// Represents a Minecraft hand + /// + public enum Hand + { + MainHand = 0, + OffHand = 1, + } +} diff --git a/MinecraftClient/Mapping/CommandBlockFlags.cs b/MinecraftClient/Mapping/CommandBlockFlags.cs new file mode 100644 index 00000000..5807222e --- /dev/null +++ b/MinecraftClient/Mapping/CommandBlockFlags.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MinecraftClient.Mapping +{ + /// + /// Represents a unit movement in the world + /// + /// + public enum CommandBlockFlags + { + TrackOutput = 0x01, + IsConditional = 0x02, + Automatic = 0x04, + } +} diff --git a/MinecraftClient/Mapping/CommandBlockMode.cs b/MinecraftClient/Mapping/CommandBlockMode.cs new file mode 100644 index 00000000..6d4aba67 --- /dev/null +++ b/MinecraftClient/Mapping/CommandBlockMode.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MinecraftClient.Mapping +{ + /// + /// Represents a unit movement in the world + /// + /// + public enum CommandBlockMode + { + Sequence = 0, + Auto = 1, + Redstone = 2, + } +} diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index bdff7eab..ffc0e148 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -759,6 +759,15 @@ namespace MinecraftClient { return inventories; } + + /// + /// Get all Entityes + /// + /// All Entities + public Dictionary GetEntities() + { + return entities; + } /// /// Get client player's inventory items @@ -825,7 +834,7 @@ namespace MinecraftClient { lock (locationLock) { - if (allowSmallTeleport && location.DistanceSquared(this.location) <= 32) + if (allowSmallTeleport) { // Allow small teleport within a range of 8 blocks. 1-step path to the desired location without checking anything UpdateLocation(location, location); // Update yaw and pitch to look at next step @@ -1037,10 +1046,22 @@ namespace MinecraftClient /// /// /// 0: interact, 1: attack, 2: interact at + /// Hand.MainHand or Hand.OffHand /// TRUE if interaction succeeded - public bool InteractEntity(int EntityID, int type) + public bool InteractEntity(int EntityID, int type, Hand hand = Hand.MainHand) { - return handler.SendInteractEntity(EntityID, type); + if (entities.ContainsKey(EntityID)) + { + if (type == 0) + { + return handler.SendInteractEntity(EntityID, type, (int)hand); + } + else + { + return handler.SendInteractEntity(EntityID, type); + } + } + else { return false; } } /// @@ -1049,9 +1070,9 @@ namespace MinecraftClient /// Location to place block to /// Block face (e.g. Direction.Down when clicking on the block below to place this block) /// TRUE if successfully placed - public bool PlaceBlock(Location location, Direction blockFace) + public bool PlaceBlock(Location location, Direction blockFace, Hand hand = Hand.MainHand) { - return handler.SendPlayerBlockPlacement(0, location, blockFace); + return handler.SendPlayerBlockPlacement((int)hand, location, blockFace); } /// @@ -1104,7 +1125,18 @@ namespace MinecraftClient // TODO Open sign editor first https://wiki.vg/Protocol#Open_Sign_Editor return handler.SendUpdateSign(location, line1, line2, line3, line4); } - + + /// + /// Update command block + /// + /// command block location + /// command + /// command block mode + /// command block flags + public bool UpdateCommandBlock(Location location, string command, CommandBlockMode mode, CommandBlockFlags flags) + { + return handler.UpdateCommandBlock(location, command, mode, flags); + } #endregion #region Event handlers: An event occurs on the Server @@ -1325,7 +1357,7 @@ namespace MinecraftClient DispatchBotEvent(bot => bot.GetText(text)); DispatchBotEvent(bot => bot.GetText(text, json)); } - + /// /// Received a connection keep-alive from the server /// @@ -1478,6 +1510,15 @@ namespace MinecraftClient entities.Add(entity.ID, entity); DispatchBotEvent(bot => bot.OnEntitySpawn(entity)); } + + /// + /// Called when an entity effects + /// + public void OnEntityEffect(int entityid, Effects effect, int amplifier, int duration, byte flags) + { + if (entities.ContainsKey(entityid)) + DispatchBotEvent(bot => bot.OnEntityEffect(entities[entityid], effect, amplifier, duration, flags)); + } /// /// Called when a player spawns or enters the client's render distance @@ -1724,7 +1765,32 @@ namespace MinecraftClient { DispatchBotEvent(bot => bot.OnTitle(action, titletext, subtitletext, actionbartext, fadein, stay, fadeout, json)); } - + + /// + /// Called when coreboardObjective + /// + /// objective name + /// 0 to create the scoreboard. 1 to remove the scoreboard. 2 to update the display text. + /// Only if mode is 0 or 2. The text to be displayed for the score + /// Only if mode is 0 or 2. 0 = "integer", 1 = "hearts". + public void OnScoreboardObjective(string objectivename, byte mode, string objectivevalue, int type) + { + string json = objectivevalue; + objectivevalue = ChatParser.ParseText(objectivevalue); + DispatchBotEvent(bot => bot.OnScoreboardObjective(objectivename, mode, objectivevalue, type, json)); + } + + /// + /// Called when DisplayScoreboard + /// + /// The entity whose score this is. For players, this is their username; for other entities, it is their UUID. + /// 0 to create/update an item. 1 to remove an item. + /// The name of the objective the score belongs to + /// he score to be displayed next to the entry. Only sent when Action does not equal 1. + public void OnUpdateScore(string entityname, byte action, string objectivename, int value) + { + DispatchBotEvent(bot => bot.OnUpdateScore(entityname, action, objectivename, value)); + } #endregion } } diff --git a/MinecraftClient/MinecraftClient.csproj b/MinecraftClient/MinecraftClient.csproj index 9d89fbef..8c763436 100644 --- a/MinecraftClient/MinecraftClient.csproj +++ b/MinecraftClient/MinecraftClient.csproj @@ -110,6 +110,8 @@ + + @@ -315,4 +317,4 @@ --> - \ No newline at end of file + diff --git a/MinecraftClient/Protocol/EntityActionType.cs b/MinecraftClient/Protocol/EntityActionType.cs index 7d560e07..bda20370 100644 --- a/MinecraftClient/Protocol/EntityActionType.cs +++ b/MinecraftClient/Protocol/EntityActionType.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -7,10 +7,14 @@ namespace MinecraftClient.Protocol { public enum EntityActionType { - StartSneaking, - StopSneaking, - LeaveBed, - StartSprinting, - StopSprinting + StartSneaking = 0, + StopSneaking = 1, + LeaveBed = 2, + StartSprinting = 3, + StopSprinting = 4, + StartJumpWithHorse = 5, + StopJumpWithHorse = 6, + OpenHorseInventory = 7, + StartFlyingWithElytra = 8, } -} \ No newline at end of file +} diff --git a/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs b/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs index fcc86cb7..a1fbeca2 100644 --- a/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs +++ b/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs @@ -45,6 +45,7 @@ namespace MinecraftClient.Protocol.Handlers EntityTeleport, EntityEquipment, EntityVelocity, + EntityEffect, TimeUpdate, UpdateHealth, SetExperience, @@ -52,7 +53,9 @@ namespace MinecraftClient.Protocol.Handlers Explosion, MapData, Title, - + ScoreboardObjective, + UpdateScore, + /// /// Represents a packet not implemented in MCC. /// diff --git a/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs b/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs index d59418c5..eaee99ee 100644 --- a/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs +++ b/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs @@ -35,5 +35,6 @@ namespace MinecraftClient.Protocol.Handlers Animation, PlayerDigging, UpdateSign, + UpdateCommandBlock, } } diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index c6fe04d5..329e89f5 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -687,7 +687,17 @@ namespace MinecraftClient.Protocol.Handlers { return false; //Currently not implemented } - + + public bool SendInteractEntity(int EntityID, int type, int hand) + { + return false; //Currently not implemented + } + + public bool UpdateCommandBlock(Location location, string command, CommandBlockMode mode, CommandBlockFlags flags) + { + return false; //Currently not implemented + } + public bool SendUseItem(int hand) { return false; //Currently not implemented diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 018e546a..8ab202ea 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -12,6 +12,9 @@ using MinecraftClient.Mapping.BlockPalettes; using MinecraftClient.Mapping.EntityPalettes; using MinecraftClient.Protocol.Handlers.Forge; using MinecraftClient.Inventory; +using System.Windows.Forms; +using System.Data.SqlClient; +using System.Diagnostics; namespace MinecraftClient.Protocol.Handlers { @@ -369,17 +372,17 @@ namespace MinecraftClient.Protocol.Handlers } break; case PacketIncomingType.MapData: - int mapid = dataTypes.ReadNextVarInt(packetData); - byte scale = dataTypes.ReadNextByte(packetData); - bool trackingposition = dataTypes.ReadNextBool(packetData); - bool locked = false; - if (protocolversion >= MC114Version) - { - locked = dataTypes.ReadNextBool(packetData); - } - int iconcount = dataTypes.ReadNextVarInt(packetData); - handler.OnMapData(mapid, scale, trackingposition, locked, iconcount); - break; + int mapid = dataTypes.ReadNextVarInt(packetData); + byte scale = dataTypes.ReadNextByte(packetData); + bool trackingposition = dataTypes.ReadNextBool(packetData); + bool locked = false; + if (protocolversion >= MC114Version) + { + locked = dataTypes.ReadNextBool(packetData); + } + int iconcount = dataTypes.ReadNextVarInt(packetData); + handler.OnMapData(mapid, scale, trackingposition, locked, iconcount); + break; case PacketIncomingType.Title: if (protocolversion >= MC18Version) { @@ -719,7 +722,7 @@ namespace MinecraftClient.Protocol.Handlers handler.OnEntityEquipment(entityid, slot2, item); } break; - case PacketIncomingType.SpawnLivingEntity: + case PacketIncomingType.SpawnLivingEntity: if (handler.GetEntityHandlingEnabled()) { Entity entity = dataTypes.ReadNextEntity(packetData, entityPalette, true); @@ -745,6 +748,20 @@ namespace MinecraftClient.Protocol.Handlers handler.OnSpawnPlayer(EntityID, UUID, EntityLocation, Yaw, Pitch); } break; + case PacketIncomingType.EntityEffect: + if (handler.GetEntityHandlingEnabled()) + { + int entityid = dataTypes.ReadNextVarInt(packetData); + Inventory.Effects effect = Effects.Speed; + if (Enum.TryParse(dataTypes.ReadNextByte(packetData).ToString(), out effect)) + { + int amplifier = dataTypes.ReadNextByte(packetData); + int duration = dataTypes.ReadNextVarInt(packetData); + byte flags = dataTypes.ReadNextByte(packetData); + handler.OnEntityEffect(entityid, effect, amplifier, duration, flags); + } + } + break; case PacketIncomingType.DestroyEntities: if (handler.GetEntityHandlingEnabled()) { @@ -867,6 +884,29 @@ namespace MinecraftClient.Protocol.Handlers byte slot = dataTypes.ReadNextByte(packetData); handler.OnHeldItemChange(slot); break; + case PacketIncomingType.ScoreboardObjective: + string objectivename = dataTypes.ReadNextString(packetData); + byte mode = dataTypes.ReadNextByte(packetData); + string objectivevalue = String.Empty; + int type2 = -1; + if (mode == 0 || mode == 2) + { + objectivevalue = dataTypes.ReadNextString(packetData); + type2 = dataTypes.ReadNextVarInt(packetData); + } + handler.OnScoreboardObjective(objectivename, mode, objectivevalue, type2); + break; + case PacketIncomingType.UpdateScore: + string entityname = dataTypes.ReadNextString(packetData); + byte action3 = dataTypes.ReadNextByte(packetData); + string objectivename2 = dataTypes.ReadNextString(packetData); + int value = -1; + if (action3 != 1) + { + value = dataTypes.ReadNextVarInt(packetData); + } + handler.OnUpdateScore(entityname, action3, objectivename2, value); + break; default: return false; //Ignored packet } @@ -1078,6 +1118,7 @@ namespace MinecraftClient.Protocol.Handlers /// Completed text IEnumerable IAutoComplete.AutoComplete(string BehindCursor) { + if (String.IsNullOrEmpty(BehindCursor)) return new string[] { }; @@ -1117,9 +1158,13 @@ namespace MinecraftClient.Protocol.Handlers SendPacket(PacketOutgoingType.TabComplete, tabcomplete_packet); int wait_left = 50; //do not wait more than 5 seconds (50 * 100 ms) - while (wait_left > 0 && !autocomplete_received) { System.Threading.Thread.Sleep(100); wait_left--; } - if (autocomplete_result.Count > 0) - ConsoleIO.WriteLineFormatted("§8" + String.Join(" ", autocomplete_result), false); + Thread t1 = new Thread(new ThreadStart(delegate + { + while (wait_left > 0 && !autocomplete_received) { System.Threading.Thread.Sleep(100); wait_left--; } + if (autocomplete_result.Count > 0) + ConsoleIO.WriteLineFormatted("§8" + String.Join(" ", autocomplete_result), false); + })); + t1.Start(); return autocomplete_result; } @@ -1418,6 +1463,21 @@ namespace MinecraftClient.Protocol.Handlers catch (System.IO.IOException) { return false; } catch (ObjectDisposedException) { return false; } } + public bool SendInteractEntity(int EntityID, int type, int hand) + { + try + { + List fields = new List(); + fields.AddRange(dataTypes.GetVarInt(EntityID)); + fields.AddRange(dataTypes.GetVarInt(type)); + fields.AddRange(dataTypes.GetVarInt(hand)); + SendPacket(PacketOutgoingType.InteractEntity, fields); + return true; + } + catch (SocketException) { return false; } + catch (System.IO.IOException) { return false; } + catch (ObjectDisposedException) { return false; } + } public bool SendInteractEntity(int EntityID, int type, float X, float Y, float Z) { return false; @@ -1645,5 +1705,26 @@ namespace MinecraftClient.Protocol.Handlers catch (System.IO.IOException) { return false; } catch (ObjectDisposedException) { return false; } } + + public bool UpdateCommandBlock(Location location, string command, CommandBlockMode mode, CommandBlockFlags flags) + { + if (protocolversion <= MC113Version) + { + try + { + List packet = new List(); + packet.AddRange(dataTypes.GetLocation(location)); + packet.AddRange(dataTypes.GetString(command)); + packet.AddRange(dataTypes.GetVarInt((int)mode)); + packet.Add((byte)flags); + SendPacket(PacketOutgoingType.UpdateSign, packet); + return true; + } + catch (SocketException) { return false; } + catch (System.IO.IOException) { return false; } + catch (ObjectDisposedException) { return false; } + } + else { return false; } + } } } diff --git a/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs b/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs index a988feb3..b6e792d8 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs @@ -59,6 +59,7 @@ namespace MinecraftClient.Protocol.Handlers case 0x18: return PacketIncomingType.EntityTeleport; case 0x12: return PacketIncomingType.EntityVelocity; case 0x04: return PacketIncomingType.EntityEquipment; + case 0x1E: return PacketIncomingType.EntityEffect; case 0x03: return PacketIncomingType.TimeUpdate; case 0x06: return PacketIncomingType.UpdateHealth; case 0x1F: return PacketIncomingType.SetExperience; @@ -66,6 +67,8 @@ namespace MinecraftClient.Protocol.Handlers case 0x27: return PacketIncomingType.Explosion; case 0x34: return PacketIncomingType.MapData; case 0x45: return PacketIncomingType.Title; + case 0x3B: return PacketIncomingType.ScoreboardObjective; + case 0x3C: return PacketIncomingType.UpdateScore; } } else if (protocol <= Protocol18Handler.MC1112Version) // MC 1.9, 1.10 and 1.11 @@ -103,6 +106,7 @@ namespace MinecraftClient.Protocol.Handlers case 0x49: return PacketIncomingType.EntityTeleport; case 0x3B: return PacketIncomingType.EntityVelocity; case 0x3C: return PacketIncomingType.EntityEquipment; + case 0x4B: return PacketIncomingType.EntityEffect; case 0x44: return PacketIncomingType.TimeUpdate; case 0x3E: return PacketIncomingType.UpdateHealth; case 0x3D: return PacketIncomingType.SetExperience; @@ -110,6 +114,8 @@ namespace MinecraftClient.Protocol.Handlers case 0x1C: return PacketIncomingType.Explosion; case 0x24: return PacketIncomingType.MapData; case 0x45: return PacketIncomingType.Title; + case 0x3F: return PacketIncomingType.ScoreboardObjective; + case 0x42: return PacketIncomingType.UpdateScore; } } else if (protocol <= Protocol18Handler.MC112Version) // MC 1.12.0 @@ -147,6 +153,7 @@ namespace MinecraftClient.Protocol.Handlers case 0x4B: return PacketIncomingType.EntityTeleport; case 0x3D: return PacketIncomingType.EntityVelocity; case 0x3E: return PacketIncomingType.EntityEquipment; + case 0x4E: return PacketIncomingType.EntityEffect; case 0x46: return PacketIncomingType.TimeUpdate; case 0x40: return PacketIncomingType.UpdateHealth; case 0x3F: return PacketIncomingType.SetExperience; @@ -154,6 +161,8 @@ namespace MinecraftClient.Protocol.Handlers case 0x1C: return PacketIncomingType.Explosion; case 0x24: return PacketIncomingType.MapData; case 0x47: return PacketIncomingType.Title; + case 0x41: return PacketIncomingType.ScoreboardObjective; + case 0x44: return PacketIncomingType.UpdateScore; } } else if (protocol <= Protocol18Handler.MC1122Version) // MC 1.12.2 @@ -191,6 +200,7 @@ namespace MinecraftClient.Protocol.Handlers case 0x4C: return PacketIncomingType.EntityTeleport; case 0x3E: return PacketIncomingType.EntityVelocity; case 0x3F: return PacketIncomingType.EntityEquipment; + case 0x4F: return PacketIncomingType.EntityEffect; case 0x47: return PacketIncomingType.TimeUpdate; case 0x41: return PacketIncomingType.UpdateHealth; case 0x40: return PacketIncomingType.SetExperience; @@ -198,6 +208,8 @@ namespace MinecraftClient.Protocol.Handlers case 0x1C: return PacketIncomingType.Explosion; case 0x25: return PacketIncomingType.MapData; case 0x48: return PacketIncomingType.Title; + case 0x42: return PacketIncomingType.ScoreboardObjective; + case 0x45: return PacketIncomingType.UpdateScore; } } else if (protocol < Protocol18Handler.MC114Version) // MC 1.13 to 1.13.2 @@ -235,6 +247,7 @@ namespace MinecraftClient.Protocol.Handlers case 0x50: return PacketIncomingType.EntityTeleport; case 0x41: return PacketIncomingType.EntityVelocity; case 0x42: return PacketIncomingType.EntityEquipment; + case 0x53: return PacketIncomingType.EntityEffect; case 0x4A: return PacketIncomingType.TimeUpdate; case 0x44: return PacketIncomingType.UpdateHealth; case 0x43: return PacketIncomingType.SetExperience; @@ -242,6 +255,8 @@ namespace MinecraftClient.Protocol.Handlers case 0x1E: return PacketIncomingType.Explosion; case 0x26: return PacketIncomingType.MapData; case 0x4B: return PacketIncomingType.Title; + case 0x45: return PacketIncomingType.ScoreboardObjective; + case 0x48: return PacketIncomingType.UpdateScore; } } else if (protocol < Protocol18Handler.MC115Version) // MC 1.14 to 1.14.4 @@ -279,6 +294,7 @@ namespace MinecraftClient.Protocol.Handlers case 0x56: return PacketIncomingType.EntityTeleport; case 0x41: return PacketIncomingType.EntityVelocity; case 0x42: return PacketIncomingType.EntityEquipment; + case 0x59: return PacketIncomingType.EntityEffect; case 0x4E: return PacketIncomingType.TimeUpdate; case 0x48: return PacketIncomingType.UpdateHealth; case 0x45: return PacketIncomingType.SetExperience; @@ -286,6 +302,8 @@ namespace MinecraftClient.Protocol.Handlers case 0x1C: return PacketIncomingType.Explosion; case 0x26: return PacketIncomingType.MapData; case 0x4F: return PacketIncomingType.Title; + case 0x49: return PacketIncomingType.ScoreboardObjective; + case 0x4C: return PacketIncomingType.UpdateScore; } } else if (protocol <= Protocol18Handler.MC1152Version) // MC 1.15 to 1.15.2 @@ -323,6 +341,7 @@ namespace MinecraftClient.Protocol.Handlers case 0x57: return PacketIncomingType.EntityTeleport; case 0x46: return PacketIncomingType.EntityVelocity; case 0x47: return PacketIncomingType.EntityEquipment; + case 0x5A: return PacketIncomingType.EntityEffect; case 0x4F: return PacketIncomingType.TimeUpdate; case 0x49: return PacketIncomingType.UpdateHealth; case 0x48: return PacketIncomingType.SetExperience; @@ -330,6 +349,9 @@ namespace MinecraftClient.Protocol.Handlers case 0x1D: return PacketIncomingType.Explosion; case 0x27: return PacketIncomingType.MapData; case 0x50: return PacketIncomingType.Title; + case 0x4A: return PacketIncomingType.ScoreboardObjective; + case 0x4D: return PacketIncomingType.UpdateScore; + } } else { switch (packetID) @@ -365,6 +387,7 @@ namespace MinecraftClient.Protocol.Handlers case 0x56: return PacketIncomingType.EntityTeleport; case 0x46: return PacketIncomingType.EntityVelocity; case 0x47: return PacketIncomingType.EntityEquipment; + case 0x5A: return PacketIncomingType.EntityEffect; case 0x4E: return PacketIncomingType.TimeUpdate; case 0x49: return PacketIncomingType.UpdateHealth; case 0x48: return PacketIncomingType.SetExperience; @@ -372,6 +395,8 @@ namespace MinecraftClient.Protocol.Handlers case 0x1C: return PacketIncomingType.Explosion; case 0x26: return PacketIncomingType.MapData; case 0x4F: return PacketIncomingType.Title; + case 0x4A: return PacketIncomingType.ScoreboardObjective; + case 0x4D: return PacketIncomingType.UpdateScore; } } @@ -417,6 +442,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.Animation: return 0x0A; case PacketOutgoingType.PlayerDigging: return 0x07; case PacketOutgoingType.UpdateSign: return 0x12; + case PacketOutgoingType.UpdateCommandBlock: return 0x20; } } else if (protocol <= Protocol18Handler.MC1112Version) // MC 1.9, 1,10 and 1.11 @@ -444,6 +470,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.Animation: return 0x1A; case PacketOutgoingType.PlayerDigging: return 0x13; case PacketOutgoingType.UpdateSign: return 0x19; + case PacketOutgoingType.UpdateCommandBlock: return 0x20; } } else if (protocol <= Protocol18Handler.MC112Version) // MC 1.12 @@ -471,6 +498,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.Animation: return 0x1D; case PacketOutgoingType.PlayerDigging: return 0x14; case PacketOutgoingType.UpdateSign: return 0x1C; + case PacketOutgoingType.UpdateCommandBlock: return 0x20; } } else if (protocol <= Protocol18Handler.MC1122Version) // 1.12.2 @@ -498,6 +526,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.Animation: return 0x1D; case PacketOutgoingType.PlayerDigging: return 0x14; case PacketOutgoingType.UpdateSign: return 0x1C; + case PacketOutgoingType.UpdateCommandBlock: return 0x20; } } else if (protocol < Protocol18Handler.MC114Version) // MC 1.13 to 1.13.2 @@ -525,6 +554,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.Animation: return 0x27; case PacketOutgoingType.PlayerDigging: return 0x18; case PacketOutgoingType.UpdateSign: return 0x26; + case PacketOutgoingType.UpdateCommandBlock: return 0x22; } } else if (protocol <= Protocol18Handler.MC1152Version) //MC 1.14 to 1.15.2 @@ -552,6 +582,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.Animation: return 0x2A; case PacketOutgoingType.PlayerDigging: return 0x1A; case PacketOutgoingType.UpdateSign: return 0x29; + case PacketOutgoingType.UpdateCommandBlock: return 0x24; } } else @@ -579,6 +610,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.Animation: return 0x2B; case PacketOutgoingType.PlayerDigging: return 0x1B; case PacketOutgoingType.UpdateSign: return 0x2A; + case PacketOutgoingType.UpdateCommandBlock: return 0x24; } } diff --git a/MinecraftClient/Protocol/IMinecraftCom.cs b/MinecraftClient/Protocol/IMinecraftCom.cs index 546b0dc5..cd444827 100644 --- a/MinecraftClient/Protocol/IMinecraftCom.cs +++ b/MinecraftClient/Protocol/IMinecraftCom.cs @@ -131,6 +131,15 @@ namespace MinecraftClient.Protocol /// Z coordinate for "interact at" /// True if packet was successfully sent bool SendInteractEntity(int EntityID, int type, float X, float Y, float Z); + + /// + /// Send an entity interaction packet to the server. + /// + /// Entity ID to interact with + /// Type of interaction (0: interact, 1: attack, 2: interact at) + /// Only if Type is interact or interact at; 0: main hand, 1: off hand + /// True if packet was successfully sent + bool SendInteractEntity(int EntityID, int type, int hand); /// /// Send a use item packet to the server @@ -202,5 +211,14 @@ namespace MinecraftClient.Protocol /// New line 4 /// True if packet was succcessfully sent bool SendUpdateSign(Location location, string line1, string line2, string line3, string line4); + + /// + /// Update command block + /// + /// command block location + /// command + /// command block mode + /// command block flags + bool UpdateCommandBlock(Location location, string command, CommandBlockMode mode, CommandBlockFlags flags); } } diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs index 69c70e4e..40ddcf81 100644 --- a/MinecraftClient/Protocol/IMinecraftComHandler.cs +++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs @@ -273,5 +273,33 @@ namespace MinecraftClient.Protocol /// /// Player entity ID void OnReceivePlayerEntityID(int EntityID); + + /// + /// Called when the Entity use effects + /// + /// entity ID + /// effect id + /// effect amplifier + /// effect duration + /// effect flags + void OnEntityEffect(int entityid, Effects effect, int amplifier, int duration, byte flags); + + /// + /// Called when coreboardObjective + /// + /// objective name + /// 0 to create the scoreboard. 1 to remove the scoreboard. 2 to update the display text. + /// Only if mode is 0 or 2. The text to be displayed for the score + /// Only if mode is 0 or 2. 0 = "integer", 1 = "hearts". + void OnScoreboardObjective(string objectivename, byte mode, string objectivevalue, int type); + + /// + /// Called when DisplayScoreboard + /// + /// The entity whose score this is. For players, this is their username; for other entities, it is their UUID. + /// 0 to create/update an item. 1 to remove an item. + /// The name of the objective the score belongs to + /// he score to be displayed next to the entry. Only sent when Action does not equal 1. + void OnUpdateScore(string entityname, byte action, string objectivename, int value); } }