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; } ///