diff --git a/MinecraftClient/Commands/Move.cs b/MinecraftClient/Commands/Move.cs
index 56fde8e3..7ccd3ed5 100644
--- a/MinecraftClient/Commands/Move.cs
+++ b/MinecraftClient/Commands/Move.cs
@@ -76,7 +76,7 @@ namespace MinecraftClient.Commands
int z = int.Parse(args[2]);
Location goal = new Location(x, y, z);
- if (handler.GetWorld().GetChunkColumn(goal) == null)
+ if (handler.GetWorld().GetChunkColumn(goal) == null || handler.GetWorld().GetChunkColumn(goal).FullyLoaded == false)
return Translations.Get("cmd.move.chunk_not_loaded");
else if (handler.MoveTo(goal, allowUnsafe: takeRisk))
return Translations.Get("cmd.move.walk", goal);
diff --git a/MinecraftClient/Mapping/ChunkColumn.cs b/MinecraftClient/Mapping/ChunkColumn.cs
index a7e704ce..5cbeda73 100644
--- a/MinecraftClient/Mapping/ChunkColumn.cs
+++ b/MinecraftClient/Mapping/ChunkColumn.cs
@@ -13,6 +13,8 @@ namespace MinecraftClient.Mapping
{
public int ColumnSize;
+ public bool FullyLoaded = false;
+
///
/// Blocks contained into the chunk
///
diff --git a/MinecraftClient/Mapping/Movement.cs b/MinecraftClient/Mapping/Movement.cs
index fc66ca7a..ff2e4089 100644
--- a/MinecraftClient/Mapping/Movement.cs
+++ b/MinecraftClient/Mapping/Movement.cs
@@ -31,9 +31,11 @@ namespace MinecraftClient.Mapping
belowFoots = location;
belowFoots.Y = Math.Truncate(location.Y);
}
+ //Console.WriteLine("IsOnGround = " + IsOnGround(world, location));
if (!IsOnGround(world, location) && !IsSwimming(world, location))
{
- while (!IsOnGround(world, belowFoots) && belowFoots.Y >= 1)
+ while (!IsOnGround(world, belowFoots) &&
+ belowFoots.Y >= 1 + (world.GetDimension() == null ? 0 : world.GetDimension().minY))
belowFoots = Move(belowFoots, Direction.Down);
location = Move2Steps(location, belowFoots, ref motionY, true).Dequeue();
}
@@ -262,6 +264,9 @@ namespace MinecraftClient.Mapping
/// True if the specified location is on the ground
public static bool IsOnGround(World world, Location location)
{
+ if (world.GetChunkColumn(location) == null || world.GetChunkColumn(location).FullyLoaded == false)
+ return true; // avoid moving downward in a not loaded chunk
+
return world.GetBlock(Move(location, Direction.Down)).Type.IsSolid()
&& (location.Y <= Math.Truncate(location.Y) + 0.0001);
}
diff --git a/MinecraftClient/Mapping/World.cs b/MinecraftClient/Mapping/World.cs
index b324007a..c753708b 100644
--- a/MinecraftClient/Mapping/World.cs
+++ b/MinecraftClient/Mapping/World.cs
@@ -26,6 +26,13 @@ namespace MinecraftClient.Mapping
///
private readonly ReaderWriterLockSlim chunksLock = new ReaderWriterLockSlim();
+ ///
+ /// Chunk data parsing progress
+ ///
+ public uint chunkCnt = 0;
+ public uint chunkLoadNotCompleted = 0;
+
+
///
/// Read, set or unload the specified chunk column
///
diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs
index 2f517021..e3a9cab0 100644
--- a/MinecraftClient/McClient.cs
+++ b/MinecraftClient/McClient.cs
@@ -59,6 +59,8 @@ namespace MinecraftClient
private float playerYaw;
private float playerPitch;
private double motionY;
+ private int chunkLoadingStateTicks = 30; // Setting it to zero to disable chunk loading statu log
+ private double lastChunkLoadedRatio = 0;
private string host;
private int port;
@@ -385,6 +387,26 @@ namespace MinecraftClient
taskToRun();
}
}
+
+ if (terrainAndMovementsEnabled)
+ {
+ if (chunkLoadingStateTicks <= 0)
+ {
+ chunkLoadingStateTicks = 50;
+ if (world.chunkCnt != 0)
+ {
+ double chunkLoadedRatio = (world.chunkCnt - world.chunkLoadNotCompleted) / (double)world.chunkCnt;
+ if (chunkLoadedRatio != lastChunkLoadedRatio)
+ {
+ Log.Info(string.Format("Chunk loading: {0:P} {1}/{2}",
+ chunkLoadedRatio, world.chunkCnt - world.chunkLoadNotCompleted, world.chunkCnt));
+ lastChunkLoadedRatio = chunkLoadedRatio;
+ }
+ }
+ }
+ else
+ chunkLoadingStateTicks--;
+ }
}
#region Connection Lost and Disconnect from Server
diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs
index cd8f831e..687cd9cd 100644
--- a/MinecraftClient/Protocol/Handlers/Protocol18.cs
+++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs
@@ -475,7 +475,10 @@ namespace MinecraftClient.Protocol.Handlers
int dataSize = dataTypes.ReadNextVarInt(packetData); // Size
new Task(() =>
{
+ handler.GetWorld().chunkCnt++;
+ handler.GetWorld().chunkLoadNotCompleted++;
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, verticalStripBitmask, packetData);
+ handler.GetWorld().chunkLoadNotCompleted--;
}).Start();
}
else
@@ -628,9 +631,12 @@ namespace MinecraftClient.Protocol.Handlers
if (protocolversion >= MC1162Version)
{
long chunkSection = dataTypes.ReadNextLong(packetData);
- int sectionX = (int)((chunkSection >> 42) & 0x3FFFFF);
- int sectionZ = (int)((chunkSection >> 20) & 0x3FFFFF);
- int sectionY = (int)((chunkSection) & 0xFFFFF);
+ int sectionX = (int)(chunkSection >> 42);
+ int sectionY = (int)((chunkSection << 44) >> 44);
+ int sectionZ = (int)((chunkSection << 22) >> 42);
+ //int sectionX = (int)((chunkSection >> 42) & 0x3FFFFF);
+ //int sectionZ = (int)((chunkSection >> 20) & 0x3FFFFF);
+ //int sectionY = (int)((chunkSection) & 0xFFFFF);
dataTypes.ReadNextBool(packetData); // Useless boolean (Related to light update)
int blocksSize = dataTypes.ReadNextVarInt(packetData);
for (int i = 0; i < blocksSize; i++)
@@ -750,6 +756,10 @@ namespace MinecraftClient.Protocol.Handlers
{
int chunkX = dataTypes.ReadNextInt(packetData);
int chunkZ = dataTypes.ReadNextInt(packetData);
+
+ if (handler.GetWorld()[chunkX, chunkZ] != null)
+ handler.GetWorld().chunkCnt--;
+
handler.GetWorld()[chunkX, chunkZ] = null;
}
break;
diff --git a/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs b/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs
index f2a22b9f..6416c303 100644
--- a/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs
+++ b/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs
@@ -147,8 +147,8 @@ namespace MinecraftClient.Protocol.Handlers
public void ProcessChunkColumnData(int chunkX, int chunkZ, ulong[] verticalStripBitmask, Queue cache)
{
var world = handler.GetWorld();
- while (world.GetDimension() == null)
- ; // Dimension parsing unfinished
+ if (world.GetDimension() == null)
+ return;
int chunkColumnSize = (world.GetDimension().height + 15) / 16;
@@ -207,6 +207,7 @@ namespace MinecraftClient.Protocol.Handlers
// Don't worry about skipping remaining data since there is no useful data afterwards in 1.9
// (plus, it would require parsing the tile entity lists' NBT)
}
+ handler.GetWorld()[chunkX, chunkZ].FullyLoaded = true;
}
///