mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
Bug fix: Cancel chunk load task when switching worlds
This commit is contained in:
parent
e150bd569b
commit
01ef9a89ca
7 changed files with 127 additions and 31 deletions
|
|
@ -71,6 +71,11 @@ namespace MinecraftClient.Commands
|
||||||
case "get": return handler.GetCurrentLocation().ToString();
|
case "get": return handler.GetCurrentLocation().ToString();
|
||||||
default: return Translations.Get("cmd.look.unknown", args[0]);
|
default: return Translations.Get("cmd.look.unknown", args[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Location goal = Movement.Move(handler.GetCurrentLocation(), direction);
|
||||||
|
if (handler.GetWorld().GetChunkColumn(goal) == null || handler.GetWorld().GetChunkColumn(goal)!.FullyLoaded == false)
|
||||||
|
return Translations.Get("cmd.move.chunk_not_loaded");
|
||||||
|
|
||||||
if (Movement.CanMove(handler.GetWorld(), handler.GetCurrentLocation(), direction))
|
if (Movement.CanMove(handler.GetWorld(), handler.GetCurrentLocation(), direction))
|
||||||
{
|
{
|
||||||
if (handler.MoveTo(Movement.Move(handler.GetCurrentLocation(), direction), allowUnsafe: takeRisk))
|
if (handler.MoveTo(Movement.Move(handler.GetCurrentLocation(), direction), allowUnsafe: takeRisk))
|
||||||
|
|
@ -88,7 +93,7 @@ namespace MinecraftClient.Commands
|
||||||
int z = int.Parse(args[2]);
|
int z = int.Parse(args[2]);
|
||||||
Location goal = new Location(x, y, z);
|
Location goal = new Location(x, y, z);
|
||||||
|
|
||||||
if (handler.GetWorld().GetChunkColumn(goal) == null || handler.GetWorld().GetChunkColumn(goal).FullyLoaded == false)
|
if (handler.GetWorld().GetChunkColumn(goal) == null || handler.GetWorld().GetChunkColumn(goal)!.FullyLoaded == false)
|
||||||
return Translations.Get("cmd.move.chunk_not_loaded");
|
return Translations.Get("cmd.move.chunk_not_loaded");
|
||||||
|
|
||||||
Location current = handler.GetCurrentLocation();
|
Location current = handler.GetCurrentLocation();
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ namespace MinecraftClient.Mapping
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="location">Location, a modulo will be applied</param>
|
/// <param name="location">Location, a modulo will be applied</param>
|
||||||
/// <returns>The chunk, or null if not loaded</returns>
|
/// <returns>The chunk, or null if not loaded</returns>
|
||||||
public Chunk GetChunk(Location location)
|
public Chunk? GetChunk(Location location)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,9 @@ namespace MinecraftClient.Mapping
|
||||||
/// Read, set or unload the specified chunk column
|
/// Read, set or unload the specified chunk column
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="chunkX">ChunkColumn X</param>
|
/// <param name="chunkX">ChunkColumn X</param>
|
||||||
/// <param name="chunkY">ChunkColumn Y</param>
|
/// <param name="chunkZ">ChunkColumn Z</param>
|
||||||
/// <returns>chunk at the given location</returns>
|
/// <returns>chunk at the given location</returns>
|
||||||
public ChunkColumn this[int chunkX, int chunkZ]
|
public ChunkColumn? this[int chunkX, int chunkZ]
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
@ -114,7 +114,7 @@ namespace MinecraftClient.Mapping
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="location">Location to retrieve chunk column</param>
|
/// <param name="location">Location to retrieve chunk column</param>
|
||||||
/// <returns>The chunk column</returns>
|
/// <returns>The chunk column</returns>
|
||||||
public ChunkColumn GetChunkColumn(Location location)
|
public ChunkColumn? GetChunkColumn(Location location)
|
||||||
{
|
{
|
||||||
return this[location.ChunkX, location.ChunkZ];
|
return this[location.ChunkX, location.ChunkZ];
|
||||||
}
|
}
|
||||||
|
|
@ -126,10 +126,10 @@ namespace MinecraftClient.Mapping
|
||||||
/// <returns>Block at specified location or Air if the location is not loaded</returns>
|
/// <returns>Block at specified location or Air if the location is not loaded</returns>
|
||||||
public Block GetBlock(Location location)
|
public Block GetBlock(Location location)
|
||||||
{
|
{
|
||||||
ChunkColumn column = GetChunkColumn(location);
|
ChunkColumn? column = GetChunkColumn(location);
|
||||||
if (column != null)
|
if (column != null)
|
||||||
{
|
{
|
||||||
Chunk chunk = column.GetChunk(location);
|
Chunk? chunk = column.GetChunk(location);
|
||||||
if (chunk != null)
|
if (chunk != null)
|
||||||
return chunk.GetBlock(location);
|
return chunk.GetBlock(location);
|
||||||
}
|
}
|
||||||
|
|
@ -188,10 +188,10 @@ namespace MinecraftClient.Mapping
|
||||||
/// <param name="block">Block to set</param>
|
/// <param name="block">Block to set</param>
|
||||||
public void SetBlock(Location location, Block block)
|
public void SetBlock(Location location, Block block)
|
||||||
{
|
{
|
||||||
ChunkColumn column = this[location.ChunkX, location.ChunkZ];
|
ChunkColumn? column = this[location.ChunkX, location.ChunkZ];
|
||||||
if (column != null)
|
if (column != null && column.ColumnSize >= location.ChunkY)
|
||||||
{
|
{
|
||||||
Chunk chunk = column[location.ChunkY];
|
Chunk? chunk = column.GetChunk(location);
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
column[location.ChunkY] = chunk = new Chunk();
|
column[location.ChunkY] = chunk = new Chunk();
|
||||||
chunk[location.ChunkBlockX, location.ChunkBlockY, location.ChunkBlockZ] = block;
|
chunk[location.ChunkBlockX, location.ChunkBlockY, location.ChunkBlockZ] = block;
|
||||||
|
|
@ -207,6 +207,8 @@ namespace MinecraftClient.Mapping
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
chunks = new Dictionary<int, Dictionary<int, ChunkColumn>>();
|
chunks = new Dictionary<int, Dictionary<int, ChunkColumn>>();
|
||||||
|
chunkCnt = 0;
|
||||||
|
chunkLoadNotCompleted = 0;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ namespace MinecraftClient
|
||||||
private float playerYaw;
|
private float playerYaw;
|
||||||
private float playerPitch;
|
private float playerPitch;
|
||||||
private double motionY;
|
private double motionY;
|
||||||
|
private CancellationTokenSource chunkProcessCancelSource = new();
|
||||||
public enum MovementType { Sneak, Walk, Sprint}
|
public enum MovementType { Sneak, Walk, Sprint}
|
||||||
public int currentMovementSpeed = 4;
|
public int currentMovementSpeed = 4;
|
||||||
private int sequenceId; // User for player block synchronization (Aka. digging, placing blocks, etc..)
|
private int sequenceId; // User for player block synchronization (Aka. digging, placing blocks, etc..)
|
||||||
|
|
@ -111,6 +112,7 @@ namespace MinecraftClient
|
||||||
public int GetSequenceId() { return sequenceId; }
|
public int GetSequenceId() { return sequenceId; }
|
||||||
public float GetPitch() { return playerPitch; }
|
public float GetPitch() { return playerPitch; }
|
||||||
public World GetWorld() { return world; }
|
public World GetWorld() { return world; }
|
||||||
|
public CancellationToken GetChunkProcessCancelToken() { return chunkProcessCancelSource.Token; }
|
||||||
public Double GetServerTPS() { return averageTPS; }
|
public Double GetServerTPS() { return averageTPS; }
|
||||||
public bool GetIsSupportPreviewsChat() { return isSupportPreviewsChat; }
|
public bool GetIsSupportPreviewsChat() { return isSupportPreviewsChat; }
|
||||||
public float GetHealth() { return playerHealth; }
|
public float GetHealth() { return playerHealth; }
|
||||||
|
|
@ -475,7 +477,9 @@ namespace MinecraftClient
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void OnConnectionLost(ChatBot.DisconnectReason reason, string message)
|
public void OnConnectionLost(ChatBot.DisconnectReason reason, string message)
|
||||||
{
|
{
|
||||||
|
chunkProcessCancelSource.Cancel();
|
||||||
world.Clear();
|
world.Clear();
|
||||||
|
chunkProcessCancelSource = new();
|
||||||
|
|
||||||
if (timeoutdetector != null)
|
if (timeoutdetector != null)
|
||||||
{
|
{
|
||||||
|
|
@ -768,6 +772,17 @@ namespace MinecraftClient
|
||||||
InvokeOnMainThread(() => { task(); return true; });
|
InvokeOnMainThread(() => { task(); return true; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear all tasks
|
||||||
|
/// </summary>
|
||||||
|
public void ClearTasks()
|
||||||
|
{
|
||||||
|
lock (threadTasksLock)
|
||||||
|
{
|
||||||
|
threadTasks.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if running on a different thread and InvokeOnMainThread is required
|
/// Check if running on a different thread and InvokeOnMainThread is required
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -892,7 +907,9 @@ namespace MinecraftClient
|
||||||
terrainAndMovementsEnabled = false;
|
terrainAndMovementsEnabled = false;
|
||||||
terrainAndMovementsRequested = false;
|
terrainAndMovementsRequested = false;
|
||||||
locationReceived = false;
|
locationReceived = false;
|
||||||
|
chunkProcessCancelSource.Cancel();
|
||||||
world.Clear();
|
world.Clear();
|
||||||
|
chunkProcessCancelSource = new();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1922,6 +1939,8 @@ namespace MinecraftClient
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void OnRespawn()
|
public void OnRespawn()
|
||||||
{
|
{
|
||||||
|
ClearTasks();
|
||||||
|
|
||||||
if (terrainAndMovementsRequested)
|
if (terrainAndMovementsRequested)
|
||||||
{
|
{
|
||||||
terrainAndMovementsEnabled = true;
|
terrainAndMovementsEnabled = true;
|
||||||
|
|
@ -1931,7 +1950,9 @@ namespace MinecraftClient
|
||||||
|
|
||||||
if (terrainAndMovementsEnabled)
|
if (terrainAndMovementsEnabled)
|
||||||
{
|
{
|
||||||
|
chunkProcessCancelSource.Cancel();
|
||||||
world.Clear();
|
world.Clear();
|
||||||
|
chunkProcessCancelSource = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
entities.Clear();
|
entities.Clear();
|
||||||
|
|
|
||||||
|
|
@ -533,6 +533,11 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
case PacketTypesIn.ChunkData:
|
case PacketTypesIn.ChunkData:
|
||||||
if (handler.GetTerrainEnabled())
|
if (handler.GetTerrainEnabled())
|
||||||
{
|
{
|
||||||
|
CancellationToken cancellationToken = handler.GetChunkProcessCancelToken();
|
||||||
|
|
||||||
|
Interlocked.Increment(ref handler.GetWorld().chunkCnt);
|
||||||
|
Interlocked.Increment(ref handler.GetWorld().chunkLoadNotCompleted);
|
||||||
|
|
||||||
int chunkX = dataTypes.ReadNextInt(packetData);
|
int chunkX = dataTypes.ReadNextInt(packetData);
|
||||||
int chunkZ = dataTypes.ReadNextInt(packetData);
|
int chunkZ = dataTypes.ReadNextInt(packetData);
|
||||||
if (protocolversion >= MC_1_17_Version)
|
if (protocolversion >= MC_1_17_Version)
|
||||||
|
|
@ -540,7 +545,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
ulong[]? verticalStripBitmask = null;
|
ulong[]? verticalStripBitmask = null;
|
||||||
|
|
||||||
if (protocolversion == MC_1_17_Version || protocolversion == MC_1_17_1_Version)
|
if (protocolversion == MC_1_17_Version || protocolversion == MC_1_17_1_Version)
|
||||||
verticalStripBitmask = dataTypes.ReadNextULongArray(packetData); // Bit Mask Le:ngth and Primary Bit Mask
|
verticalStripBitmask = dataTypes.ReadNextULongArray(packetData); // Bit Mask Length and Primary Bit Mask
|
||||||
|
|
||||||
dataTypes.ReadNextNbt(packetData); // Heightmaps
|
dataTypes.ReadNextNbt(packetData); // Heightmaps
|
||||||
|
|
||||||
|
|
@ -548,20 +553,20 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
{
|
{
|
||||||
int biomesLength = dataTypes.ReadNextVarInt(packetData); // Biomes length
|
int biomesLength = dataTypes.ReadNextVarInt(packetData); // Biomes length
|
||||||
for (int i = 0; i < biomesLength; i++)
|
for (int i = 0; i < biomesLength; i++)
|
||||||
{
|
|
||||||
dataTypes.SkipNextVarInt(packetData); // Biomes
|
dataTypes.SkipNextVarInt(packetData); // Biomes
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int dataSize = dataTypes.ReadNextVarInt(packetData); // Size
|
int dataSize = dataTypes.ReadNextVarInt(packetData); // Size
|
||||||
|
|
||||||
Interlocked.Increment(ref handler.GetWorld().chunkCnt);
|
|
||||||
Interlocked.Increment(ref handler.GetWorld().chunkLoadNotCompleted);
|
|
||||||
new Task(() =>
|
new Task(() =>
|
||||||
{
|
{
|
||||||
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, verticalStripBitmask, packetData);
|
bool loaded = pTerrain.ProcessChunkColumnData(chunkX, chunkZ, verticalStripBitmask, packetData, cancellationToken);
|
||||||
Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted);
|
if (loaded)
|
||||||
|
Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted);
|
||||||
}).Start();
|
}).Start();
|
||||||
|
|
||||||
|
// Block Entity data: ignored
|
||||||
|
// Light data: ignored
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -579,7 +584,9 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
byte[] decompressed = ZlibUtils.Decompress(compressed);
|
byte[] decompressed = ZlibUtils.Decompress(compressed);
|
||||||
new Task(() =>
|
new Task(() =>
|
||||||
{
|
{
|
||||||
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, addBitmap, currentDimension == 0, chunksContinuous, currentDimension, new Queue<byte>(decompressed));
|
bool loaded = pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, addBitmap, currentDimension == 0, chunksContinuous, currentDimension, new Queue<byte>(decompressed), cancellationToken);
|
||||||
|
if (loaded)
|
||||||
|
Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted);
|
||||||
}).Start();
|
}).Start();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -606,7 +613,9 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
int dataSize = dataTypes.ReadNextVarInt(packetData);
|
int dataSize = dataTypes.ReadNextVarInt(packetData);
|
||||||
new Task(() =>
|
new Task(() =>
|
||||||
{
|
{
|
||||||
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, currentDimension, packetData);
|
bool loaded = pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, currentDimension, packetData, cancellationToken);
|
||||||
|
if (loaded)
|
||||||
|
Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted);
|
||||||
}).Start();
|
}).Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -825,6 +834,8 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
case PacketTypesIn.MapChunkBulk:
|
case PacketTypesIn.MapChunkBulk:
|
||||||
if (protocolversion < MC_1_9_Version && handler.GetTerrainEnabled())
|
if (protocolversion < MC_1_9_Version && handler.GetTerrainEnabled())
|
||||||
{
|
{
|
||||||
|
CancellationToken cancellationToken = handler.GetChunkProcessCancelToken();
|
||||||
|
|
||||||
int chunkCount;
|
int chunkCount;
|
||||||
bool hasSkyLight;
|
bool hasSkyLight;
|
||||||
Queue<byte> chunkData = packetData;
|
Queue<byte> chunkData = packetData;
|
||||||
|
|
@ -861,8 +872,18 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
//Process chunk records
|
//Process chunk records
|
||||||
for (int chunkColumnNo = 0; chunkColumnNo < chunkCount; chunkColumnNo++)
|
new Task(() =>
|
||||||
pTerrain.ProcessChunkColumnData(chunkXs[chunkColumnNo], chunkZs[chunkColumnNo], chunkMasks[chunkColumnNo], addBitmaps[chunkColumnNo], hasSkyLight, true, currentDimension, chunkData);
|
{
|
||||||
|
for (int chunkColumnNo = 0; chunkColumnNo < chunkCount; chunkColumnNo++)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
break;
|
||||||
|
bool loaded = pTerrain.ProcessChunkColumnData(chunkXs[chunkColumnNo], chunkZs[chunkColumnNo], chunkMasks[chunkColumnNo], addBitmaps[chunkColumnNo], hasSkyLight, true, currentDimension, chunkData, cancellationToken);
|
||||||
|
if (loaded)
|
||||||
|
Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted);
|
||||||
|
}
|
||||||
|
}).Start();
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PacketTypesIn.UnloadChunk:
|
case PacketTypesIn.UnloadChunk:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
//using System.Linq;
|
//using System.Linq;
|
||||||
//using System.Text;
|
//using System.Text;
|
||||||
using MinecraftClient.Mapping;
|
using MinecraftClient.Mapping;
|
||||||
|
|
@ -32,7 +33,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="chunk">Blocks will store in this chunk</param>
|
/// <param name="chunk">Blocks will store in this chunk</param>
|
||||||
/// <param name="cache">Cache for reading data</param>
|
/// <param name="cache">Cache for reading data</param>
|
||||||
private Chunk ReadBlockStatesField(ref Chunk chunk, Queue<byte> cache)
|
private Chunk? ReadBlockStatesField(ref Chunk chunk, Queue<byte> cache)
|
||||||
{
|
{
|
||||||
// read Block states (Type: Paletted Container)
|
// read Block states (Type: Paletted Container)
|
||||||
byte bitsPerEntry = dataTypes.ReadNextByte(cache);
|
byte bitsPerEntry = dataTypes.ReadNextByte(cache);
|
||||||
|
|
@ -144,8 +145,13 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
/// <param name="chunkZ">Chunk Z location</param>
|
/// <param name="chunkZ">Chunk Z location</param>
|
||||||
/// <param name="verticalStripBitmask">Chunk mask for reading data, store in bitset, used in 1.17 and 1.17.1</param>
|
/// <param name="verticalStripBitmask">Chunk mask for reading data, store in bitset, used in 1.17 and 1.17.1</param>
|
||||||
/// <param name="cache">Cache for reading chunk data</param>
|
/// <param name="cache">Cache for reading chunk data</param>
|
||||||
public void ProcessChunkColumnData(int chunkX, int chunkZ, ulong[] verticalStripBitmask, Queue<byte> cache)
|
/// <param name="cancellationToken">token to cancel the task</param>
|
||||||
|
/// <returns>true if successfully loaded</returns>
|
||||||
|
public bool ProcessChunkColumnData(int chunkX, int chunkZ, ulong[]? verticalStripBitmask, Queue<byte> cache, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return false;
|
||||||
|
|
||||||
var world = handler.GetWorld();
|
var world = handler.GetWorld();
|
||||||
|
|
||||||
int chunkColumnSize = (World.GetDimension().height + 15) / 16; // Round up
|
int chunkColumnSize = (World.GetDimension().height + 15) / 16; // Round up
|
||||||
|
|
@ -156,12 +162,15 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
// Unloading chunks is handled by a separate packet
|
// Unloading chunks is handled by a separate packet
|
||||||
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
|
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
|
||||||
{
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return false;
|
||||||
|
|
||||||
// 1.18 and above always contains all chunk section in data
|
// 1.18 and above always contains all chunk section in data
|
||||||
// 1.17 and 1.17.1 need vertical strip bitmask to know if the chunk section is included
|
// 1.17 and 1.17.1 need vertical strip bitmask to know if the chunk section is included
|
||||||
if ((protocolversion >= Protocol18Handler.MC_1_18_1_Version) ||
|
if ((protocolversion >= Protocol18Handler.MC_1_18_1_Version) ||
|
||||||
(((protocolversion == Protocol18Handler.MC_1_17_Version) ||
|
(((protocolversion == Protocol18Handler.MC_1_17_Version) ||
|
||||||
(protocolversion == Protocol18Handler.MC_1_17_1_Version)) &&
|
(protocolversion == Protocol18Handler.MC_1_17_1_Version)) &&
|
||||||
((verticalStripBitmask[chunkY / 64] & (1UL << (chunkY % 64))) != 0)))
|
((verticalStripBitmask![chunkY / 64] & (1UL << (chunkY % 64))) != 0)))
|
||||||
{
|
{
|
||||||
// Non-air block count inside chunk section, for lighting purposes
|
// Non-air block count inside chunk section, for lighting purposes
|
||||||
int blockCnt = dataTypes.ReadNextShort(cache);
|
int blockCnt = dataTypes.ReadNextShort(cache);
|
||||||
|
|
@ -170,12 +179,16 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
Chunk chunk = new Chunk();
|
Chunk chunk = new Chunk();
|
||||||
ReadBlockStatesField(ref chunk, cache);
|
ReadBlockStatesField(ref chunk, cache);
|
||||||
|
|
||||||
|
// check before store chunk
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return false;
|
||||||
|
|
||||||
//We have our chunk, save the chunk into the world
|
//We have our chunk, save the chunk into the world
|
||||||
handler.InvokeOnMainThread(() =>
|
handler.InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (handler.GetWorld()[chunkX, chunkZ] == null)
|
if (handler.GetWorld()[chunkX, chunkZ] == null)
|
||||||
handler.GetWorld()[chunkX, chunkZ] = new ChunkColumn(chunkColumnSize);
|
handler.GetWorld()[chunkX, chunkZ] = new ChunkColumn(chunkColumnSize);
|
||||||
handler.GetWorld()[chunkX, chunkZ][chunkY] = chunk;
|
handler.GetWorld()[chunkX, chunkZ]![chunkY] = chunk;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Skip Read Biomes (Type: Paletted Container) - 1.18(1.18.1) and above
|
// Skip Read Biomes (Type: Paletted Container) - 1.18(1.18.1) and above
|
||||||
|
|
@ -205,7 +218,12 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
// Don't worry about skipping remaining data since there is no useful data afterwards in 1.9
|
// 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)
|
// (plus, it would require parsing the tile entity lists' NBT)
|
||||||
}
|
}
|
||||||
handler.GetWorld()[chunkX, chunkZ].FullyLoaded = true;
|
handler.InvokeOnMainThread(() =>
|
||||||
|
{
|
||||||
|
if (handler.GetWorld()[chunkX, chunkZ] != null)
|
||||||
|
handler.GetWorld()[chunkX, chunkZ]!.FullyLoaded = true;
|
||||||
|
});
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -219,8 +237,13 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
/// <param name="chunksContinuous">Are the chunk continuous</param>
|
/// <param name="chunksContinuous">Are the chunk continuous</param>
|
||||||
/// <param name="currentDimension">Current dimension type (0 = overworld)</param>
|
/// <param name="currentDimension">Current dimension type (0 = overworld)</param>
|
||||||
/// <param name="cache">Cache for reading chunk data</param>
|
/// <param name="cache">Cache for reading chunk data</param>
|
||||||
public void ProcessChunkColumnData(int chunkX, int chunkZ, ushort chunkMask, ushort chunkMask2, bool hasSkyLight, bool chunksContinuous, int currentDimension, Queue<byte> cache)
|
/// <param name="cancellationToken">token to cancel the task</param>
|
||||||
|
/// <returns>true if successfully loaded</returns>
|
||||||
|
public bool ProcessChunkColumnData(int chunkX, int chunkZ, ushort chunkMask, ushort chunkMask2, bool hasSkyLight, bool chunksContinuous, int currentDimension, Queue<byte> cache, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return false;
|
||||||
|
|
||||||
const int chunkColumnSize = 16;
|
const int chunkColumnSize = 16;
|
||||||
if (protocolversion >= Protocol18Handler.MC_1_9_Version)
|
if (protocolversion >= Protocol18Handler.MC_1_9_Version)
|
||||||
{
|
{
|
||||||
|
|
@ -228,6 +251,9 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
// Unloading chunks is handled by a separate packet
|
// Unloading chunks is handled by a separate packet
|
||||||
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
|
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
|
||||||
{
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return false;
|
||||||
|
|
||||||
if ((chunkMask & (1 << chunkY)) != 0)
|
if ((chunkMask & (1 << chunkY)) != 0)
|
||||||
{
|
{
|
||||||
// 1.14 and above Non-air block count inside chunk section, for lighting purposes
|
// 1.14 and above Non-air block count inside chunk section, for lighting purposes
|
||||||
|
|
@ -343,12 +369,16 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check before store chunk
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return false;
|
||||||
|
|
||||||
//We have our chunk, save the chunk into the world
|
//We have our chunk, save the chunk into the world
|
||||||
handler.InvokeOnMainThread(() =>
|
handler.InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (handler.GetWorld()[chunkX, chunkZ] == null)
|
if (handler.GetWorld()[chunkX, chunkZ] == null)
|
||||||
handler.GetWorld()[chunkX, chunkZ] = new ChunkColumn();
|
handler.GetWorld()[chunkX, chunkZ] = new ChunkColumn();
|
||||||
handler.GetWorld()[chunkX, chunkZ][chunkY] = chunk;
|
handler.GetWorld()[chunkX, chunkZ]![chunkY] = chunk;
|
||||||
});
|
});
|
||||||
|
|
||||||
//Pre-1.14 Lighting data
|
//Pre-1.14 Lighting data
|
||||||
|
|
@ -384,6 +414,9 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
//Load chunk data from the server
|
//Load chunk data from the server
|
||||||
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
|
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
|
||||||
{
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return false;
|
||||||
|
|
||||||
if ((chunkMask & (1 << chunkY)) != 0)
|
if ((chunkMask & (1 << chunkY)) != 0)
|
||||||
{
|
{
|
||||||
Chunk chunk = new Chunk();
|
Chunk chunk = new Chunk();
|
||||||
|
|
@ -395,12 +428,16 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
for (int blockX = 0; blockX < Chunk.SizeX; blockX++)
|
for (int blockX = 0; blockX < Chunk.SizeX; blockX++)
|
||||||
chunk[blockX, blockY, blockZ] = new Block(queue.Dequeue());
|
chunk[blockX, blockY, blockZ] = new Block(queue.Dequeue());
|
||||||
|
|
||||||
|
// check before store chunk
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return false;
|
||||||
|
|
||||||
//We have our chunk, save the chunk into the world
|
//We have our chunk, save the chunk into the world
|
||||||
handler.InvokeOnMainThread(() =>
|
handler.InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (handler.GetWorld()[chunkX, chunkZ] == null)
|
if (handler.GetWorld()[chunkX, chunkZ] == null)
|
||||||
handler.GetWorld()[chunkX, chunkZ] = new ChunkColumn();
|
handler.GetWorld()[chunkX, chunkZ] = new ChunkColumn();
|
||||||
handler.GetWorld()[chunkX, chunkZ][chunkY] = chunk;
|
handler.GetWorld()[chunkX, chunkZ]![chunkY] = chunk;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -479,17 +516,26 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
for (int blockX = 0; blockX < Chunk.SizeX; blockX++)
|
for (int blockX = 0; blockX < Chunk.SizeX; blockX++)
|
||||||
chunk[blockX, blockY, blockZ] = new Block(blockTypes.Dequeue(), blockMeta.Dequeue());
|
chunk[blockX, blockY, blockZ] = new Block(blockTypes.Dequeue(), blockMeta.Dequeue());
|
||||||
|
|
||||||
|
// check before store chunk
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
return false;
|
||||||
|
|
||||||
handler.InvokeOnMainThread(() =>
|
handler.InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (handler.GetWorld()[chunkX, chunkZ] == null)
|
if (handler.GetWorld()[chunkX, chunkZ] == null)
|
||||||
handler.GetWorld()[chunkX, chunkZ] = new ChunkColumn();
|
handler.GetWorld()[chunkX, chunkZ] = new ChunkColumn();
|
||||||
handler.GetWorld()[chunkX, chunkZ][chunkY] = chunk;
|
handler.GetWorld()[chunkX, chunkZ]![chunkY] = chunk;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handler.GetWorld()[chunkX, chunkZ].FullyLoaded = true;
|
handler.InvokeOnMainThread(() =>
|
||||||
|
{
|
||||||
|
if (handler.GetWorld()[chunkX, chunkZ] != null)
|
||||||
|
handler.GetWorld()[chunkX, chunkZ]!.FullyLoaded = true;
|
||||||
|
});
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ namespace MinecraftClient.Protocol
|
||||||
PlayerInfo? GetPlayerInfo(Guid uuid);
|
PlayerInfo? GetPlayerInfo(Guid uuid);
|
||||||
Location GetCurrentLocation();
|
Location GetCurrentLocation();
|
||||||
World GetWorld();
|
World GetWorld();
|
||||||
|
public System.Threading.CancellationToken GetChunkProcessCancelToken();
|
||||||
bool GetIsSupportPreviewsChat();
|
bool GetIsSupportPreviewsChat();
|
||||||
bool GetTerrainEnabled();
|
bool GetTerrainEnabled();
|
||||||
bool SetTerrainEnabled(bool enabled);
|
bool SetTerrainEnabled(bool enabled);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue