Fix /move

This commit is contained in:
BruceChen 2022-09-09 16:13:25 +08:00
parent 531f3408a0
commit 223c13561c
6 changed files with 62 additions and 45 deletions

View file

@ -82,7 +82,8 @@ namespace MinecraftClient.Commands
{ {
if (handler.MoveTo(goal, allowUnsafe: takeRisk)) if (handler.MoveTo(goal, allowUnsafe: takeRisk))
return Translations.Get("cmd.move.moving", args[0]); return Translations.Get("cmd.move.moving", args[0]);
else return takeRisk ? Translations.Get("cmd.move.dir_fail") : Translations.Get("cmd.move.suggestforce"); else
return takeRisk ? Translations.Get("cmd.move.dir_fail") : Translations.Get("cmd.move.suggestforce");
} }
else return Translations.Get("cmd.move.dir_fail"); else return Translations.Get("cmd.move.dir_fail");
} }
@ -90,7 +91,7 @@ namespace MinecraftClient.Commands
{ {
try try
{ {
Location current = handler.GetCurrentLocation(), currentCenter = new Location(current).ConvertToCenter(); Location current = handler.GetCurrentLocation(), currentCenter = current.ToCenter();
double x = args[0].StartsWith('~') ? current.X + (args[0].Length > 1 ? double.Parse(args[0][1..]) : 0) : double.Parse(args[0]); 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 y = args[1].StartsWith('~') ? current.Y + (args[1].Length > 1 ? double.Parse(args[1][1..]) : 0) : double.Parse(args[1]);
@ -103,7 +104,7 @@ namespace MinecraftClient.Commands
if (takeRisk || Movement.PlayerFitsHere(handler.GetWorld(), goal)) if (takeRisk || Movement.PlayerFitsHere(handler.GetWorld(), goal))
{ {
if (current.DistanceSquared(goal) <= 1.5) if (current.ToFloor() == goal.ToFloor())
handler.MoveTo(goal, allowDirectTeleport: true); handler.MoveTo(goal, allowDirectTeleport: true);
else if (!handler.MoveTo(goal, allowUnsafe: takeRisk)) else if (!handler.MoveTo(goal, allowUnsafe: takeRisk))
return takeRisk ? Translations.Get("cmd.move.fail", goal) : Translations.Get("cmd.move.suggestforce", goal); return takeRisk ? Translations.Get("cmd.move.fail", goal) : Translations.Get("cmd.move.suggestforce", goal);

View file

@ -141,7 +141,7 @@ namespace MinecraftClient.Mapping
/// <param name="location">Entity location</param> /// <param name="location">Entity location</param>
/// <param name="uuid">Player uuid</param> /// <param name="uuid">Player uuid</param>
/// <param name="name">Player name</param> /// <param name="name">Player name</param>
public Entity(int ID, EntityType type, Location location, Guid uuid, string? name) public Entity(int ID, EntityType type, Location location, Guid uuid, string? name, byte yaw, byte pitch)
{ {
this.ID = ID; this.ID = ID;
this.Type = type; this.Type = type;
@ -151,6 +151,8 @@ namespace MinecraftClient.Mapping
this.Health = 1.0f; this.Health = 1.0f;
this.Equipment = new Dictionary<int, Item>(); this.Equipment = new Dictionary<int, Item>();
this.Item = new Item(ItemType.Air, 0, null); this.Item = new Item(ItemType.Air, 0, null);
this.Yaw = yaw * (1 / 256) * 360; // to angle in 360 degree
this.Pitch = pitch * (1 / 256) * 360;
} }
} }
} }

View file

@ -76,24 +76,19 @@ namespace MinecraftClient.Mapping
/// <summary> /// <summary>
/// Round coordinates /// Round coordinates
/// </summary> /// </summary>
/// <returns>itself</returns> /// <returns>New location</returns>
public Location ConvertToFloor() public Location ToFloor()
{ {
this.X = Math.Floor(this.X); return new Location(Math.Floor(this.X), Math.Floor(this.Y), Math.Floor(this.Z));
this.Y = Math.Floor(this.Y);
this.Z = Math.Floor(this.Z);
return this;
} }
/// <summary> /// <summary>
/// Get the center coordinates /// Get the center coordinates
/// </summary> /// </summary>
/// <returns>itself</returns> /// <returns>New location</returns>
public Location ConvertToCenter() public Location ToCenter()
{ {
this.X = Math.Floor(this.X) + 0.5; return new Location(Math.Floor(this.X) + 0.5, this.Y, Math.Floor(this.Z) + 0.5);
this.Z = Math.Floor(this.Z) + 0.5;
return this;
} }
/// <summary> /// <summary>

View file

@ -49,14 +49,18 @@ namespace MinecraftClient.Mapping
/// <param name="location">Location the player is currently at</param> /// <param name="location">Location the player is currently at</param>
/// <param name="allowUnsafe">Allow possible but unsafe locations</param> /// <param name="allowUnsafe">Allow possible but unsafe locations</param>
/// <returns>A list of new locations the player can move to</returns> /// <returns>A list of new locations the player can move to</returns>
public static IEnumerable<Location> GetAvailableMoves(World world, Location location, bool allowUnsafe = false) public static IEnumerable<Location> GetAvailableMoves(World world, Location originLocation, bool allowUnsafe = false)
{ {
List<Location> availableMoves = new List<Location>(); Location location = originLocation.ToCenter();
List<Location> availableMoves = new();
if (IsOnGround(world, location) || IsSwimming(world, location)) if (IsOnGround(world, location) || IsSwimming(world, location))
{ {
foreach (Direction dir in Enum.GetValues(typeof(Direction))) foreach (Direction dir in Enum.GetValues(typeof(Direction)))
if (CanMove(world, location, dir) && (allowUnsafe || IsSafe(world, Move(location, dir)))) {
availableMoves.Add(Move(location, dir)); Location dest = Move(location, dir);
if (CanMove(world, location, dir) && (allowUnsafe || IsSafe(world, dest)))
availableMoves.Add(dest);
}
} }
else else
{ {
@ -98,7 +102,8 @@ namespace MinecraftClient.Mapping
Y += motionY; Y += motionY;
if (Y < goal.Y) if (Y < goal.Y)
return new Queue<Location>(new[] { goal }); return new Queue<Location>(new[] { goal });
else return new Queue<Location>(new[] { new Location(start.X, Y, start.Z) }); else
return new Queue<Location>(new[] { new Location(start.X, Y, start.Z) });
} }
else else
{ {
@ -110,12 +115,13 @@ namespace MinecraftClient.Mapping
if (totalStepsDouble >= 1) if (totalStepsDouble >= 1)
{ {
Queue<Location> movementSteps = new Queue<Location>(); Queue<Location> movementSteps = new();
for (int i = 1; i <= totalSteps; i++) for (int i = 1; i <= totalSteps; i++)
movementSteps.Enqueue(start + step * i); movementSteps.Enqueue(start + step * i);
return movementSteps; return movementSteps;
} }
else return new Queue<Location>(new[] { goal }); else
return new Queue<Location>(new[] { goal });
} }
} }
@ -168,9 +174,8 @@ namespace MinecraftClient.Mapping
throw new ArgumentException("minOffset must be lower or equal to maxOffset", "minOffset"); throw new ArgumentException("minOffset must be lower or equal to maxOffset", "minOffset");
// Round start coordinates for easier calculation // Round start coordinates for easier calculation
Location startCenter = new Location(start).ConvertToCenter(); Location startLower = start.ToFloor();
Location startLower = new Location(start).ConvertToFloor(); Location goalLower = goal.ToFloor();
Location goalLower = new Location(goal).ConvertToFloor();
// We always use distance squared so our limits must also be squared. // We always use distance squared so our limits must also be squared.
minOffset *= minOffset; minOffset *= minOffset;
@ -206,7 +211,7 @@ namespace MinecraftClient.Mapping
// Return if goal found and no maxOffset was given OR current node is between minOffset and maxOffset // Return if goal found and no maxOffset was given OR current node is between minOffset and maxOffset
if ((current.Location == goalLower && 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, startCenter, goal); return ReconstructPath(CameFrom, current.Location, start, goal);
} }
// Discover neighbored blocks // Discover neighbored blocks
@ -235,7 +240,7 @@ namespace MinecraftClient.Mapping
//// Goal could not be reached. Set the path to the closest location if close enough //// 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)) if (current != null && (maxOffset == int.MaxValue || openSet.MinH_ScoreNode.H_score <= maxOffset))
return ReconstructPath(CameFrom, openSet.MinH_ScoreNode.Location, startCenter, goal); return ReconstructPath(CameFrom, openSet.MinH_ScoreNode.Location, start, goal);
else else
return null; return null;
} }
@ -246,32 +251,36 @@ namespace MinecraftClient.Mapping
/// <param name="Came_From">The collection of Locations that leads back to the start</param> /// <param name="Came_From">The collection of Locations that leads back to the start</param>
/// <param name="current">Endpoint of our later walk</param> /// <param name="current">Endpoint of our later walk</param>
/// <returns>the path that leads to current from the start position</returns> /// <returns>the path that leads to current from the start position</returns>
private static Queue<Location> ReconstructPath(Dictionary<Location, Location> Came_From, Location current, Location startCenter, Location end) private static Queue<Location> ReconstructPath(Dictionary<Location, Location> Came_From, Location current, Location start, Location end)
{ {
// Add 0.5 to walk over the middle of a block and avoid collisions int midPathCnt = 0;
Location center = new(0.5, 0, 0.5);
List<Location> total_path = new(); List<Location> total_path = new();
// Move from the center of the block to the final position // Move from the center of the block to the final position
if (current != end && current.DistanceSquared(end) <= 1.5) if (current != end && current == end.ToFloor())
total_path.Add(end); total_path.Add(end);
// Generate intermediate paths // Generate intermediate paths
total_path.Add(current + center); total_path.Add(current.ToCenter());
while (Came_From.ContainsKey(current)) while (Came_From.ContainsKey(current))
{ {
++midPathCnt;
current = Came_From[current]; current = Came_From[current];
total_path.Add(current + center); total_path.Add(current.ToCenter());
} }
if (midPathCnt <= 2 && start.DistanceSquared(end) < 2.0)
return new Queue<Location>(new Location[] { end });
else
{
// Move to the center of the block first // Move to the center of the block first
if (current != startCenter && current.DistanceSquared(startCenter) <= 1.5) if (current != start && current == start.ToFloor())
total_path.Add(startCenter); total_path.Add(start.ToCenter());
total_path.Reverse(); total_path.Reverse();
return new Queue<Location>(total_path); return new Queue<Location>(total_path);
} }
}
/// <summary> /// <summary>
/// A datastructure to store Locations as Nodes and provide them in sorted and queued order. /// A datastructure to store Locations as Nodes and provide them in sorted and queued order.
@ -567,7 +576,7 @@ namespace MinecraftClient.Mapping
return PlayerFitsHere(world, Move(location, Direction.North)) && PlayerFitsHere(world, Move(location, Direction.West)) && PlayerFitsHere(world, Move(location, direction)); return PlayerFitsHere(world, Move(location, Direction.North)) && PlayerFitsHere(world, Move(location, Direction.West)) && PlayerFitsHere(world, Move(location, direction));
default: default:
throw new ArgumentException("Unknown direction", "direction"); throw new ArgumentException("Unknown direction", nameof(direction));
} }
} }

View file

@ -2791,12 +2791,16 @@ namespace MinecraftClient
/// <summary> /// <summary>
/// Called when a player spawns or enters the client's render distance /// Called when a player spawns or enters the client's render distance
/// </summary> /// </summary>
public void OnSpawnPlayer(int entityID, Guid uuid, Location location, byte Yaw, byte Pitch) public void OnSpawnPlayer(int entityID, Guid uuid, Location location, byte yaw, byte pitch)
{ {
string? playerName = null; Entity playerEntity;
if (onlinePlayers.ContainsKey(uuid)) if (onlinePlayers.TryGetValue(uuid, out PlayerInfo? player))
playerName = onlinePlayers[uuid].Name; {
Entity playerEntity = new(entityID, EntityType.Player, location, uuid, playerName); playerEntity = new(entityID, EntityType.Player, location, uuid, player.Name, yaw, pitch);
player.entity = playerEntity;
}
else
playerEntity = new(entityID, EntityType.Player, location, uuid, null, yaw, pitch);
OnSpawnEntity(playerEntity); OnSpawnEntity(playerEntity);
} }

View file

@ -23,6 +23,12 @@ namespace MinecraftClient.Protocol
public string? DisplayName; public string? DisplayName;
// Entity info
public Mapping.Entity? entity;
// For message signature
private readonly PublicKey? PublicKey; private readonly PublicKey? PublicKey;
private readonly DateTime? KeyExpiresAt; private readonly DateTime? KeyExpiresAt;