mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
Merge pull request #2154 from BruceChenQAQ/master
Support for using relative coordinates in /move
This commit is contained in:
commit
7a33e65c61
5 changed files with 59 additions and 28 deletions
|
|
@ -80,7 +80,7 @@ namespace MinecraftClient
|
|||
/// <returns>Argument array or empty array if no arguments</returns>
|
||||
public static string[] getArgs(string command)
|
||||
{
|
||||
string[] args = getArg(command).Split(' ');
|
||||
string[] args = getArg(command).Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (args.Length == 1 && args[0] == "")
|
||||
{
|
||||
return new string[] { };
|
||||
|
|
|
|||
|
|
@ -90,21 +90,27 @@ namespace MinecraftClient.Commands
|
|||
{
|
||||
try
|
||||
{
|
||||
int x = int.Parse(args[0]);
|
||||
int y = int.Parse(args[1]);
|
||||
int z = int.Parse(args[2]);
|
||||
Location goal = new Location(x, y, z);
|
||||
Location current = handler.GetCurrentLocation(), currentCenter = new Location(current).ConvertToCenter();
|
||||
|
||||
double x = args[0].StartsWith('~') ? current.X + (args[0].Length > 1 ? double.Parse(args[0][1..]) : 0) : double.Parse(args[0]);
|
||||
double y = args[1].StartsWith('~') ? current.Y + (args[1].Length > 1 ? double.Parse(args[1][1..]) : 0) : double.Parse(args[1]);
|
||||
double z = args[2].StartsWith('~') ? current.Z + (args[2].Length > 1 ? double.Parse(args[2][1..]) : 0) : double.Parse(args[2]);
|
||||
Location goal = new(x, y, z);
|
||||
|
||||
ChunkColumn? chunkColumn = handler.GetWorld().GetChunkColumn(goal);
|
||||
if (chunkColumn == null || chunkColumn.FullyLoaded == false)
|
||||
return Translations.Get("cmd.move.chunk_not_loaded");
|
||||
|
||||
Location current = handler.GetCurrentLocation();
|
||||
handler.MoveTo(current.ToCenter(), allowDirectTeleport: true);
|
||||
|
||||
if (handler.MoveTo(goal, allowUnsafe: takeRisk))
|
||||
if (takeRisk || Movement.PlayerFitsHere(handler.GetWorld(), goal))
|
||||
{
|
||||
if (current.DistanceSquared(goal) <= 1.5)
|
||||
handler.MoveTo(goal, allowDirectTeleport: true);
|
||||
else if (!handler.MoveTo(goal, allowUnsafe: takeRisk))
|
||||
return takeRisk ? Translations.Get("cmd.move.fail", goal) : Translations.Get("cmd.move.suggestforce", goal);
|
||||
return Translations.Get("cmd.move.walk", goal, current);
|
||||
else return takeRisk ? Translations.Get("cmd.move.fail", goal) : Translations.Get("cmd.move.suggestforce", goal);
|
||||
}
|
||||
else
|
||||
return Translations.Get("cmd.move.suggestforce", goal);
|
||||
}
|
||||
catch (FormatException) { return GetCmdDescTranslated(); }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ namespace MinecraftClient.Mapping
|
|||
Z = z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new location
|
||||
/// </summary>
|
||||
public Location(Location loc)
|
||||
{
|
||||
X = loc.X;
|
||||
Y = loc.Y;
|
||||
Z = loc.Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new location
|
||||
/// </summary>
|
||||
|
|
@ -67,7 +77,7 @@ namespace MinecraftClient.Mapping
|
|||
/// Round coordinates
|
||||
/// </summary>
|
||||
/// <returns>itself</returns>
|
||||
public Location ToFloor()
|
||||
public Location ConvertToFloor()
|
||||
{
|
||||
this.X = Math.Floor(this.X);
|
||||
this.Y = Math.Floor(this.Y);
|
||||
|
|
@ -79,7 +89,7 @@ namespace MinecraftClient.Mapping
|
|||
/// Get the center coordinates
|
||||
/// </summary>
|
||||
/// <returns>itself</returns>
|
||||
public Location ToCenter()
|
||||
public Location ConvertToCenter()
|
||||
{
|
||||
this.X = Math.Floor(this.X) + 0.5;
|
||||
this.Z = Math.Floor(this.Z) + 0.5;
|
||||
|
|
|
|||
|
|
@ -168,8 +168,9 @@ namespace MinecraftClient.Mapping
|
|||
throw new ArgumentException("minOffset must be lower or equal to maxOffset", "minOffset");
|
||||
|
||||
// Round start coordinates for easier calculation
|
||||
start.ToFloor();
|
||||
goal.ToFloor();
|
||||
Location startCenter = new Location(start).ConvertToCenter();
|
||||
Location startLower = new Location(start).ConvertToFloor();
|
||||
Location goalLower = new Location(goal).ConvertToFloor();
|
||||
|
||||
// We always use distance squared so our limits must also be squared.
|
||||
minOffset *= minOffset;
|
||||
|
|
@ -187,8 +188,8 @@ namespace MinecraftClient.Mapping
|
|||
Dictionary<Location, int> gScoreDict = new Dictionary<Location, int>();
|
||||
|
||||
// Set start values for variables
|
||||
openSet.Insert(0, (int)start.DistanceSquared(goal), start);
|
||||
gScoreDict[start] = 0;
|
||||
openSet.Insert(0, (int)startLower.DistanceSquared(goalLower), startLower);
|
||||
gScoreDict[startLower] = 0;
|
||||
BinaryHeap.Node current = null;
|
||||
|
||||
///---///
|
||||
|
|
@ -203,9 +204,9 @@ namespace MinecraftClient.Mapping
|
|||
current = openSet.GetRootLocation();
|
||||
|
||||
// Return if goal found and no maxOffset was given OR current node is between minOffset and maxOffset
|
||||
if ((current.Location == goal && maxOffset <= 0) || (maxOffset > 0 && current.H_score >= minOffset && current.H_score <= maxOffset))
|
||||
if ((current.Location == goalLower && maxOffset <= 0) || (maxOffset > 0 && current.H_score >= minOffset && current.H_score <= maxOffset))
|
||||
{
|
||||
return ReconstructPath(CameFrom, current.Location);
|
||||
return ReconstructPath(CameFrom, current.Location, startCenter, goal);
|
||||
}
|
||||
|
||||
// Discover neighbored blocks
|
||||
|
|
@ -227,14 +228,14 @@ namespace MinecraftClient.Mapping
|
|||
|
||||
// If this location is not already included in the Binary Heap: save it
|
||||
if (!openSet.ContainsLocation(neighbor))
|
||||
openSet.Insert(tentativeGScore, (int)neighbor.DistanceSquared(goal), neighbor);
|
||||
openSet.Insert(tentativeGScore, (int)neighbor.DistanceSquared(goalLower), neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// Goal could not be reached. Set the path to the closest location if close enough
|
||||
if (current != null && (maxOffset == int.MaxValue || openSet.MinH_ScoreNode.H_score <= maxOffset))
|
||||
return ReconstructPath(CameFrom, openSet.MinH_ScoreNode.Location);
|
||||
return ReconstructPath(CameFrom, openSet.MinH_ScoreNode.Location, startCenter, goal);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
|
@ -245,15 +246,29 @@ namespace MinecraftClient.Mapping
|
|||
/// <param name="Came_From">The collection of Locations that leads back to the start</param>
|
||||
/// <param name="current">Endpoint of our later walk</param>
|
||||
/// <returns>the path that leads to current from the start position</returns>
|
||||
private static Queue<Location> ReconstructPath(Dictionary<Location, Location> Came_From, Location current)
|
||||
private static Queue<Location> ReconstructPath(Dictionary<Location, Location> Came_From, Location current, Location startCenter, Location end)
|
||||
{
|
||||
// Add 0.5 to walk over the middle of a block and avoid collisions
|
||||
List<Location> total_path = new List<Location>(new[] { current + new Location(0.5, 0, 0.5) });
|
||||
Location center = new(0.5, 0, 0.5);
|
||||
|
||||
List<Location> total_path = new();
|
||||
|
||||
// Move from the center of the block to the final position
|
||||
if (current != end && current.DistanceSquared(end) <= 1.5)
|
||||
total_path.Add(end);
|
||||
|
||||
// Generate intermediate paths
|
||||
total_path.Add(current + center);
|
||||
while (Came_From.ContainsKey(current))
|
||||
{
|
||||
current = Came_From[current];
|
||||
total_path.Add(current + new Location(0.5, 0, 0.5));
|
||||
total_path.Add(current + center);
|
||||
}
|
||||
|
||||
// Move to the center of the block first
|
||||
if (current != startCenter && current.DistanceSquared(startCenter) <= 1.5)
|
||||
total_path.Add(startCenter);
|
||||
|
||||
total_path.Reverse();
|
||||
return new Queue<Location>(total_path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1102,7 +1102,7 @@ namespace MinecraftClient
|
|||
/// <summary>
|
||||
/// Move to the specified location
|
||||
/// </summary>
|
||||
/// <param name="location">Location to reach</param>
|
||||
/// <param name="goal">Location to reach</param>
|
||||
/// <param name="allowUnsafe">Allow possible but unsafe locations thay may hurt the player: lava, cactus...</param>
|
||||
/// <param name="allowDirectTeleport">Allow non-vanilla direct teleport instead of computing path, but may cause invalid moves and/or trigger anti-cheat plugins</param>
|
||||
/// <param name="maxOffset">If no valid path can be found, also allow locations within specified distance of destination</param>
|
||||
|
|
@ -1110,21 +1110,21 @@ namespace MinecraftClient
|
|||
/// <param name="timeout">How long to wait until the path is evaluated (default: 5 seconds)</param>
|
||||
/// <remarks>When location is unreachable, computation will reach timeout, then optionally fallback to a close location within maxOffset</remarks>
|
||||
/// <returns>True if a path has been found</returns>
|
||||
public bool MoveTo(Location location, bool allowUnsafe = false, bool allowDirectTeleport = false, int maxOffset = 0, int minOffset = 0, TimeSpan? timeout = null)
|
||||
public bool MoveTo(Location goal, bool allowUnsafe = false, bool allowDirectTeleport = false, int maxOffset = 0, int minOffset = 0, TimeSpan? timeout = null)
|
||||
{
|
||||
lock (locationLock)
|
||||
{
|
||||
if (allowDirectTeleport)
|
||||
{
|
||||
// 1-step path to the desired location without checking anything
|
||||
UpdateLocation(location, location); // Update yaw and pitch to look at next step
|
||||
handler.SendLocationUpdate(location, Movement.IsOnGround(world, location), _yaw, _pitch);
|
||||
UpdateLocation(goal, goal); // Update yaw and pitch to look at next step
|
||||
handler.SendLocationUpdate(goal, Movement.IsOnGround(world, goal), _yaw, _pitch);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate path through pathfinding. Path contains a list of 1-block movement that will be divided into steps
|
||||
path = Movement.CalculatePath(world, this.location, location, allowUnsafe, maxOffset, minOffset, timeout ?? TimeSpan.FromSeconds(5));
|
||||
path = Movement.CalculatePath(world, this.location, goal, allowUnsafe, maxOffset, minOffset, timeout ?? TimeSpan.FromSeconds(5));
|
||||
return path != null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue