diff --git a/MinecraftClient/ChatBot.cs b/MinecraftClient/ChatBot.cs
index 38eb3a18..a9349d72 100644
--- a/MinecraftClient/ChatBot.cs
+++ b/MinecraftClient/ChatBot.cs
@@ -458,7 +458,7 @@ namespace MinecraftClient
protected void ReconnectToTheServer(int ExtraAttempts = 3)
{
- McTcpClient.AttemptsLeft = ExtraAttempts;
+ McTcpClient.ReconnectionAttemptsLeft = ExtraAttempts;
Program.Restart();
}
diff --git a/MinecraftClient/ChatBots/AutoRelog.cs b/MinecraftClient/ChatBots/AutoRelog.cs
index d98e30d5..2c53f585 100644
--- a/MinecraftClient/ChatBots/AutoRelog.cs
+++ b/MinecraftClient/ChatBots/AutoRelog.cs
@@ -25,14 +25,14 @@ namespace MinecraftClient.ChatBots
{
attempts = retries;
if (attempts == -1) { attempts = int.MaxValue; }
- McTcpClient.AttemptsLeft = attempts;
+ McTcpClient.ReconnectionAttemptsLeft = attempts;
delay = DelayBeforeRelog;
if (delay < 1) { delay = 1; }
}
public override void Initialize()
{
- McTcpClient.AttemptsLeft = attempts;
+ McTcpClient.ReconnectionAttemptsLeft = attempts;
if (System.IO.File.Exists(Settings.AutoRelog_KickMessagesFile))
{
dictionary = System.IO.File.ReadAllLines(Settings.AutoRelog_KickMessagesFile);
@@ -55,7 +55,7 @@ namespace MinecraftClient.ChatBots
{
LogToConsole("Waiting " + delay + " seconds before reconnecting...");
System.Threading.Thread.Sleep(delay * 1000);
- McTcpClient.AttemptsLeft = attempts;
+ McTcpClient.ReconnectionAttemptsLeft = attempts;
ReconnectToTheServer();
return true;
}
diff --git a/MinecraftClient/Mapping/Location.cs b/MinecraftClient/Mapping/Location.cs
new file mode 100644
index 00000000..22145ad5
--- /dev/null
+++ b/MinecraftClient/Mapping/Location.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Mapping
+{
+ ///
+ /// Represents a location into a Minecraft world
+ ///
+ public struct Location
+ {
+ ///
+ /// The X Coordinate
+ ///
+ public double X;
+
+ ///
+ /// The Y Coordinate (vertical)
+ ///
+ public double Y;
+
+ ///
+ /// The Z coordinate
+ ///
+ public double Z;
+
+ ///
+ /// Get location with zeroed coordinates
+ ///
+ public static Location Zero
+ {
+ get
+ {
+ return new Location(0, 0, 0);
+ }
+ }
+
+ ///
+ /// Create a new location
+ ///
+ public Location(double x, double y, double z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+
+ ///
+ /// Compare two locations. Locations are equals if the integer part of their coordinates are equals.
+ ///
+ /// Object to compare to
+ /// TRUE if the locations are equals
+ public override bool Equals(object obj)
+ {
+ if (obj == null)
+ return false;
+ if (obj is Location)
+ {
+ return ((int)this.X) == ((int)((Location)obj).X)
+ && ((int)this.Y) == ((int)((Location)obj).Y)
+ && ((int)this.Z) == ((int)((Location)obj).Z);
+ }
+ return false;
+ }
+
+ ///
+ /// Get a representation of the location as unsigned long
+ ///
+ ///
+ /// A modulo will be applied if the location is outside the following ranges:
+ /// X: -33,554,432 to +33,554,431
+ /// Y: -2,048 to +2,047
+ /// Z: -33,554,432 to +33,554,431
+ ///
+ /// Location representation as ulong
+
+ public ulong GetLongRepresentation()
+ {
+ return ((((ulong)X) & 0x3FFFFFF) << 38) | ((((ulong)Y) & 0xFFF) << 26) | (((ulong)Z) & 0x3FFFFFF);
+ }
+
+ ///
+ /// Get a location from an unsigned long.
+ ///
+ /// Location represented by the ulong
+
+ public static Location FromLongRepresentation(ulong location)
+ {
+ return new Location(location >> 38, (location >> 26) & 0xFFF, location << 38 >> 38);
+ }
+
+ ///
+ /// Compare two locations. Locations are equals if the integer part of their coordinates are equals.
+ ///
+ /// First location to compare
+ /// Second location to compare
+ /// TRUE if the locations are equals
+ public static bool operator == (Location loc1, Location loc2)
+ {
+ if (loc1 == null && loc2 == null)
+ return true;
+ if (loc1 == null || loc2 == null)
+ return false;
+ return loc1.Equals(loc2);
+ }
+
+ ///
+ /// Compare two locations. Locations are not equals if the integer part of their coordinates are not equals.
+ ///
+ /// First location to compare
+ /// Second location to compare
+ /// TRUE if the locations are equals
+ public static bool operator != (Location loc1, Location loc2)
+ {
+ if (loc1 == null && loc2 == null)
+ return true;
+ if (loc1 == null || loc2 == null)
+ return false;
+ return !loc1.Equals(loc2);
+ }
+
+ ///
+ /// Sums two locations and returns the result.
+ ///
+ ///
+ /// Thrown if one of the provided location is null
+ ///
+ /// First location to sum
+ /// Second location to sum
+ /// Sum of the two locations
+ public static Location operator + (Location loc1, Location loc2)
+ {
+ return new Location
+ (
+ loc1.X + loc2.X,
+ loc1.Y + loc2.Y,
+ loc1.Z + loc2.Z
+ );
+ }
+
+ ///
+ /// DO NOT USE. Defined to comply with C# requirements requiring a GetHashCode() when overriding Equals() or ==
+ ///
+ ///
+ /// A modulo will be applied if the location is outside the following ranges:
+ /// X: -4096 to +4095
+ /// Y: -32 to +31
+ /// Z: -4096 to +4095
+ ///
+ /// A simplified version of the location
+ public override int GetHashCode()
+ {
+ return (((int)X) & ~((~0) << 13)) << 19
+ | (((int)Y) & ~((~0) << 13)) << 13
+ | (((int)Z) & ~((~0) << 06)) << 00;
+ }
+ }
+}
diff --git a/MinecraftClient/McTcpClient.cs b/MinecraftClient/McTcpClient.cs
index e1e5c6bd..66e8bc8a 100644
--- a/MinecraftClient/McTcpClient.cs
+++ b/MinecraftClient/McTcpClient.cs
@@ -9,6 +9,7 @@ using System.Net;
using MinecraftClient.Protocol;
using MinecraftClient.Proxy;
using MinecraftClient.Protocol.Handlers.Forge;
+using MinecraftClient.Mapping;
namespace MinecraftClient
{
@@ -18,16 +19,20 @@ namespace MinecraftClient
public class McTcpClient : IMinecraftComHandler
{
- private static List cmd_names = new List();
- private static Dictionary cmds = new Dictionary();
- private List bots = new List();
+ public static int ReconnectionAttemptsLeft = 0;
+
+ private static readonly List cmd_names = new List();
+ private static readonly Dictionary cmds = new Dictionary();
private readonly Dictionary onlinePlayers = new Dictionary();
- private static List scripts_on_hold = new List();
+
+ private readonly List bots = new List();
+ private static readonly List scripts_on_hold = new List();
public void BotLoad(ChatBot b) { b.SetHandler(this); bots.Add(b); b.Initialize(); Settings.SingleCommand = ""; }
public void BotUnLoad(ChatBot b) { bots.RemoveAll(item => object.ReferenceEquals(item, b)); }
public void BotClear() { bots.Clear(); }
- public static int AttemptsLeft = 0;
+ private Location location;
+ private int updateTicks = 0;
private string host;
private int port;
@@ -40,6 +45,7 @@ namespace MinecraftClient
public string GetUsername() { return username; }
public string GetUserUUID() { return uuid; }
public string GetSessionID() { return sessionid; }
+ public Location GetCurrentLocation() { return location; }
TcpClient client;
IMinecraftCom handler;
@@ -162,10 +168,10 @@ namespace MinecraftClient
if (retry)
{
- if (AttemptsLeft > 0)
+ if (ReconnectionAttemptsLeft > 0)
{
- ConsoleIO.WriteLogLine("Waiting 5 seconds (" + AttemptsLeft + " attempts left)...");
- Thread.Sleep(5000); AttemptsLeft--; Program.Restart();
+ ConsoleIO.WriteLogLine("Waiting 5 seconds (" + ReconnectionAttemptsLeft + " attempts left)...");
+ Thread.Sleep(5000); ReconnectionAttemptsLeft--; Program.Restart();
}
else if (!singlecommand && Settings.interactiveMode)
{
@@ -330,6 +336,34 @@ namespace MinecraftClient
handler.SendBrandInfo(Settings.BrandInfo.Trim());
}
+ ///
+ /// Called when the server sends a new player location,
+ /// or if a ChatBot whishes to update the player's location.
+ ///
+ /// The new location
+ /// If true, the location is relative to the current location
+
+ public void UpdateLocation(Location location, bool relative)
+ {
+ if (relative)
+ {
+ this.location += location;
+ }
+ else this.location = location;
+ }
+
+ ///
+ /// Called when the server sends a new player location,
+ /// or if a ChatBot whishes to update the player's location.
+ ///
+ /// The new location
+ /// If true, the location is relative to the current location
+
+ public void UpdateLocation(Location location)
+ {
+ UpdateLocation(location, false);
+ }
+
///
/// Received some text from the server
///
@@ -409,6 +443,16 @@ namespace MinecraftClient
else throw; //ThreadAbortException should not be caught
}
}
+
+ if (Settings.TerrainAndMovements)
+ {
+ if (updateTicks >= 10)
+ {
+ handler.SendLocationUpdate(location, true); //TODO handle onGround once terrain data is available
+ updateTicks = 0;
+ }
+ updateTicks++;
+ }
}
///
diff --git a/MinecraftClient/MinecraftClient.csproj b/MinecraftClient/MinecraftClient.csproj
index 9c09a5e1..b9a92e7e 100644
--- a/MinecraftClient/MinecraftClient.csproj
+++ b/MinecraftClient/MinecraftClient.csproj
@@ -152,6 +152,7 @@
+
diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs
index 9e447531..12916186 100644
--- a/MinecraftClient/Program.cs
+++ b/MinecraftClient/Program.cs
@@ -19,7 +19,11 @@ namespace MinecraftClient
{
private static McTcpClient Client;
public static string[] startupargs;
+
public const string Version = "1.8.2";
+ public const string MCLowestVersion = "1.4.6";
+ public const string MCHighestVersion = "1.8.8";
+
private static Thread offlinePrompt = null;
private static bool useMcVersionOnce = false;
@@ -29,7 +33,7 @@ namespace MinecraftClient
static void Main(string[] args)
{
- Console.WriteLine("Console Client for MC 1.4.6 to 1.8.8 - v" + Version + " - By ORelio & Contributors");
+ Console.WriteLine("Console Client for MC {0} to {1} - v{2} - By ORelio & Contributors", MCLowestVersion, MCHighestVersion, Version);
//Basic Input/Output ?
if (args.Length >= 1 && args[args.Length - 1] == "BasicIO")
@@ -137,6 +141,8 @@ namespace MinecraftClient
ConsoleIcon.setPlayerIconAsync(Settings.Username);
Console.WriteLine("Success. (session ID: " + sessionID + ')');
+
+ //ProtocolHandler.RealmsListWorlds(Settings.Username, UUID, sessionID); //TODO REMOVE
if (Settings.ServerIP == "")
{
diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs
index 89cedbe6..07ee63dd 100644
--- a/MinecraftClient/Protocol/Handlers/Protocol16.cs
+++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs
@@ -7,6 +7,7 @@ using System.Threading;
using MinecraftClient.Crypto;
using MinecraftClient.Proxy;
using System.Security.Cryptography;
+using MinecraftClient.Mapping;
namespace MinecraftClient.Protocol.Handlers
{
@@ -615,6 +616,11 @@ namespace MinecraftClient.Protocol.Handlers
return false; //Only supported since MC 1.7
}
+ public bool SendLocationUpdate(Location location, bool onGround)
+ {
+ return false; //Currently not implemented
+ }
+
///
/// Send a plugin channel packet to the server.
///
diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs
index a9631206..ddb8771b 100644
--- a/MinecraftClient/Protocol/Handlers/Protocol18.cs
+++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs
@@ -8,6 +8,7 @@ using MinecraftClient.Crypto;
using MinecraftClient.Proxy;
using System.Security.Cryptography;
using MinecraftClient.Protocol.Handlers.Forge;
+using MinecraftClient.Mapping;
namespace MinecraftClient.Protocol.Handlers
{
@@ -162,6 +163,23 @@ namespace MinecraftClient.Protocol.Handlers
catch (IndexOutOfRangeException) { /* No message type */ }
handler.OnTextReceived(ChatParser.ParseText(message));
break;
+ case 0x08:
+ if (Settings.TerrainAndMovements)
+ {
+ double x = readNextDouble(ref packetData);
+ double y = readNextDouble(ref packetData);
+ double z = readNextDouble(ref packetData);
+
+ byte locMask = readNextByte(ref packetData);
+ Location location = handler.GetCurrentLocation();
+
+ location.X = (locMask & 1 << 0) != 0 ? location.X + x : x;
+ location.Y = (locMask & 1 << 1) != 0 ? location.Y + y : y;
+ location.Z = (locMask & 1 << 2) != 0 ? location.Z + z : z;
+
+ handler.UpdateLocation(location);
+ }
+ break;
case 0x38: //Player List update
if (protocolversion >= MC18Version)
{
@@ -509,6 +527,18 @@ namespace MinecraftClient.Protocol.Handlers
return readData(len, ref cache);
}
+ ///
+ /// Read a double from a cache of bytes and remove it from the cache
+ ///
+ /// The double value
+
+ private static double readNextDouble(ref byte[] cache)
+ {
+ byte[] rawValue = readData(8, ref cache);
+ Array.Reverse(rawValue); //Endianness
+ return BitConverter.ToDouble(rawValue, 0);
+ }
+
///
/// Read an integer from the network
///
@@ -602,6 +632,19 @@ namespace MinecraftClient.Protocol.Handlers
return bytes.ToArray();
}
+ ///
+ /// Get byte array representing a double
+ ///
+ /// Array to process
+ /// Array ready to send
+
+ private byte[] getDouble(double number)
+ {
+ byte[] theDouble = BitConverter.GetBytes(number);
+ Array.Reverse(theDouble); //Endianness
+ return theDouble;
+ }
+
///
/// Get byte array with length information prepended to it
///
@@ -931,6 +974,29 @@ namespace MinecraftClient.Protocol.Handlers
return SendPluginChannelPacket("MC|Brand", getString(brandInfo));
}
+ ///
+ /// Send a location update to the server
+ ///
+ /// The new location of the player
+ /// True if the player is on the ground
+ /// True if the location update was successfully sent
+
+ public bool SendLocationUpdate(Location location, bool onGround)
+ {
+ if (Settings.TerrainAndMovements)
+ {
+ try
+ {
+ SendPacket(0x04, concatBytes(
+ getDouble(location.X), getDouble(location.X), getDouble(location.X),
+ new byte[] { onGround ? (byte)1 : (byte)0 }));
+ return true;
+ }
+ catch (SocketException) { return false; }
+ }
+ else return false;
+ }
+
///
/// Send a plugin channel packet (0x17) to the server, compression and encryption will be handled automatically
///
diff --git a/MinecraftClient/Protocol/IMinecraftCom.cs b/MinecraftClient/Protocol/IMinecraftCom.cs
index 218f49d4..927258fd 100644
--- a/MinecraftClient/Protocol/IMinecraftCom.cs
+++ b/MinecraftClient/Protocol/IMinecraftCom.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using MinecraftClient.Crypto;
+using MinecraftClient.Mapping;
namespace MinecraftClient.Protocol
{
@@ -45,7 +46,7 @@ namespace MinecraftClient.Protocol
bool SendRespawnPacket();
///
- /// Tell the server what client is being used to connect to the server
+ /// Inform the server of the client being used to connect
///
/// Client string describing the client
/// True if brand info was successfully sent
@@ -53,10 +54,17 @@ namespace MinecraftClient.Protocol
bool SendBrandInfo(string brandInfo);
///
- /// Send a plugin channel packet to the server.
- ///
- /// http://dinnerbone.com/blog/2012/01/13/minecraft-plugin-channels-messaging/
+ /// Send a location update telling that we moved to that location
///
+ /// The new location
+ /// True if packet was successfully sent
+
+ bool SendLocationUpdate(Location location, bool onGround);
+
+ ///
+ /// Send a plugin channel packet to the server.
+ ///
+ ///
/// Channel to send packet on
/// packet Data
/// True if message was successfully sent
diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs
index 606e80ea..5376e31a 100644
--- a/MinecraftClient/Protocol/IMinecraftComHandler.cs
+++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using MinecraftClient.Mapping;
namespace MinecraftClient.Protocol
{
@@ -22,6 +23,7 @@ namespace MinecraftClient.Protocol
string GetUserUUID();
string GetSessionID();
string[] GetOnlinePlayers();
+ Location GetCurrentLocation();
///
/// Called when a server was successfully joined
@@ -50,6 +52,13 @@ namespace MinecraftClient.Protocol
void OnPlayerLeave(Guid uuid);
+ ///
+ /// Called when the server sets the new location for the player
+ ///
+ /// New location of the player
+
+ void UpdateLocation(Location location);
+
///
/// This method is called when the connection has been lost
///
diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs
index c0119ff1..a0c6fc5d 100644
--- a/MinecraftClient/Settings.cs
+++ b/MinecraftClient/Settings.cs
@@ -54,6 +54,7 @@ namespace MinecraftClient
public static string BrandInfo = MCCBrandInfo;
public static bool DisplaySystemMessages = true;
public static bool DisplayXPBarMessages = true;
+ public static bool TerrainAndMovements = false;
//AntiAFK Settings
public static bool AntiAFK_Enabled = false;
@@ -178,6 +179,7 @@ namespace MinecraftClient
case "scriptcache": CacheScripts = str2bool(argValue); break;
case "showsystemmessages": DisplaySystemMessages = str2bool(argValue); break;
case "showxpbarmessages": DisplayXPBarMessages = str2bool(argValue); break;
+ case "handleterrainandmovements": TerrainAndMovements = str2bool(argValue); break;
case "botowners":
Bots_Owners.Clear();
@@ -407,6 +409,7 @@ namespace MinecraftClient
+ "chatbotlogfile= #leave empty for no logfile\r\n"
+ "showsystemmessages=true #system messages for server ops\r\n"
+ "showxpbarmessages=true #messages displayed above xp bar\r\n"
+ + "handleterrainandmovements=false #requires more ram and cpu\r\n"
+ "accountlist=accounts.txt\r\n"
+ "serverlist=servers.txt\r\n"
+ "playerheadicon=true\r\n"