mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
terrain handling for 1.18(1.18.1) and 1.18.2
This commit is contained in:
parent
af574b654e
commit
516effa81d
6 changed files with 384 additions and 120 deletions
169
MinecraftClient/Mapping/Dimension.cs
Normal file
169
MinecraftClient/Mapping/Dimension.cs
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MinecraftClient.Mapping
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The dimension type, available after 1.16.2
|
||||||
|
/// </summary>
|
||||||
|
public class Dimension
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the dimension type (for example, "minecraft:overworld").
|
||||||
|
/// </summary>
|
||||||
|
public readonly string Name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether piglins shake and transform to zombified piglins.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool piglin_safe;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When false, compasses spin randomly. When true, nether portals can spawn zombified piglins.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool natural;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How much light the dimension has.
|
||||||
|
/// </summary>
|
||||||
|
public readonly float ambient_light;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set, the time of the day is the specified value.
|
||||||
|
/// Value: -1: not set
|
||||||
|
/// Value: [0, 24000]: time of the day
|
||||||
|
/// </summary>
|
||||||
|
public readonly long fixed_time = -1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A resource location defining what block tag to use for infiniburn.
|
||||||
|
/// Value: "" or minecraft resource "minecraft:...".
|
||||||
|
/// </summary>
|
||||||
|
public readonly string infiniburn;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether players can charge and use respawn anchors.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool respawn_anchor_works;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the dimension has skylight access or not.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool has_skylight;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether players can use a bed to sleep.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool bed_works;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// unknown
|
||||||
|
/// Values: "minecraft:overworld", "minecraft:the_nether", "minecraft:the_end" or something else.
|
||||||
|
/// </summary>
|
||||||
|
public readonly string effects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether players with the Bad Omen effect can cause a raid.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool has_raids;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum Y level.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int min_y = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum Y level.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int max_y = 256;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum height.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int height = 256;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum height to which chorus fruits and nether portals can bring players within this dimension.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int logical_height;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The multiplier applied to coordinates when traveling to the dimension.
|
||||||
|
/// </summary>
|
||||||
|
public readonly double coordinate_scale;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the dimensions behaves like the nether (water evaporates and sponges dry) or not. Also causes lava to spread thinner.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool ultrawarm;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the dimension has a bedrock ceiling or not. When true, causes lava to spread faster.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool has_ceiling;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create from the "Dimension Codec" NBT Tag Compound
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chunkX">ChunkColumn X</param>
|
||||||
|
/// <param name="chunkY">ChunkColumn Y</param>
|
||||||
|
/// <returns>chunk at the given location</returns>
|
||||||
|
public Dimension(string name, Dictionary<string, object> nbt)
|
||||||
|
{
|
||||||
|
if (name == null)
|
||||||
|
throw new ArgumentNullException("name");
|
||||||
|
if (nbt == null)
|
||||||
|
throw new ArgumentNullException("nbt Data");
|
||||||
|
|
||||||
|
this.Name = name;
|
||||||
|
|
||||||
|
if (nbt.ContainsKey("piglin_safe"))
|
||||||
|
this.piglin_safe = 1 == (byte)nbt["piglin_safe"];
|
||||||
|
if (nbt.ContainsKey("natural"))
|
||||||
|
this.natural = 1 == (byte)nbt["natural"];
|
||||||
|
if (nbt.ContainsKey("ambient_light"))
|
||||||
|
this.ambient_light = (float)nbt["ambient_light"];
|
||||||
|
if (nbt.ContainsKey("fixed_time"))
|
||||||
|
this.fixed_time = (long)nbt["fixed_time"];
|
||||||
|
if (nbt.ContainsKey("infiniburn"))
|
||||||
|
this.infiniburn = (string)nbt["infiniburn"];
|
||||||
|
if (nbt.ContainsKey("respawn_anchor_works"))
|
||||||
|
this.respawn_anchor_works = 1 == (byte)nbt["respawn_anchor_works"];
|
||||||
|
if (nbt.ContainsKey("has_skylight"))
|
||||||
|
this.has_skylight = 1 == (byte)nbt["has_skylight"];
|
||||||
|
if (nbt.ContainsKey("bed_works"))
|
||||||
|
this.bed_works = 1 == (byte)nbt["bed_works"];
|
||||||
|
if (nbt.ContainsKey("effects"))
|
||||||
|
this.effects = (string)nbt["effects"];
|
||||||
|
if (nbt.ContainsKey("has_raids"))
|
||||||
|
this.has_raids = 1 == (byte)nbt["has_raids"];
|
||||||
|
if (nbt.ContainsKey("min_y"))
|
||||||
|
this.min_y = (int)nbt["min_y"];
|
||||||
|
if (nbt.ContainsKey("height"))
|
||||||
|
this.height = (int)nbt["height"];
|
||||||
|
if (nbt.ContainsKey("min_y") && nbt.ContainsKey("height"))
|
||||||
|
this.max_y = this.min_y + this.height;
|
||||||
|
if (nbt.ContainsKey("logical_height"))
|
||||||
|
this.logical_height = (int)nbt["logical_height"];
|
||||||
|
if (nbt.ContainsKey("coordinate_scale"))
|
||||||
|
{
|
||||||
|
var coordinate_scale_obj = nbt["coordinate_scale"];
|
||||||
|
if (coordinate_scale_obj.GetType() == typeof(float))
|
||||||
|
this.coordinate_scale = (float)coordinate_scale_obj;
|
||||||
|
else
|
||||||
|
this.coordinate_scale = (double)coordinate_scale_obj;
|
||||||
|
}
|
||||||
|
if (nbt.ContainsKey("ultrawarm"))
|
||||||
|
this.ultrawarm = 1 == (byte)nbt["ultrawarm"];
|
||||||
|
if (nbt.ContainsKey("has_ceiling"))
|
||||||
|
this.has_ceiling = 1 == (byte)nbt["has_ceiling"];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,11 @@ namespace MinecraftClient.Mapping
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Z;
|
public double Z;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current world: to get the lowest Y coordinate
|
||||||
|
/// </summary>
|
||||||
|
public static World world;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get location with zeroed coordinates
|
/// Get location with zeroed coordinates
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -79,7 +84,10 @@ namespace MinecraftClient.Mapping
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (int)Math.Floor(Y / Chunk.SizeY);
|
if (world.GetDimension() == null)
|
||||||
|
return (int)Math.Floor(Y / Chunk.SizeY); // old version, always start at zero
|
||||||
|
else
|
||||||
|
return (int)Math.Floor((Y - world.GetDimension().min_y) / Chunk.SizeY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@ namespace MinecraftClient.Mapping
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Dictionary<int, Dictionary<int, ChunkColumn>> chunks = new Dictionary<int, Dictionary<int, ChunkColumn>>();
|
private Dictionary<int, Dictionary<int, ChunkColumn>> chunks = new Dictionary<int, Dictionary<int, ChunkColumn>>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The dimension info of the world
|
||||||
|
/// </summary>
|
||||||
|
private Dimension dimension;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock for thread safety
|
/// Lock for thread safety
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -78,6 +83,30 @@ namespace MinecraftClient.Mapping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public World()
|
||||||
|
{
|
||||||
|
Location.world = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set dimension type
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"> The name of the dimension type</param>
|
||||||
|
/// <param name="nbt">The dimension type (NBT Tag Compound)</param>
|
||||||
|
public void SetDimension(string name, Dictionary<string, object> nbt)
|
||||||
|
{
|
||||||
|
this.dimension = new Dimension(name, nbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get dimension type
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The chunk column</returns>
|
||||||
|
public Dimension GetDimension()
|
||||||
|
{
|
||||||
|
return this.dimension;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get chunk column at the specified location
|
/// Get chunk column at the specified location
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -176,6 +205,7 @@ namespace MinecraftClient.Mapping
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
chunks = new Dictionary<int, Dictionary<int, ChunkColumn>>();
|
chunks = new Dictionary<int, Dictionary<int, ChunkColumn>>();
|
||||||
|
dimension = null;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@
|
||||||
<Compile Include="ChatBots\AutoDrop.cs" />
|
<Compile Include="ChatBots\AutoDrop.cs" />
|
||||||
<Compile Include="ChatBots\Mailer.cs" />
|
<Compile Include="ChatBots\Mailer.cs" />
|
||||||
<Compile Include="Commands\SetRnd.cs" />
|
<Compile Include="Commands\SetRnd.cs" />
|
||||||
|
<Compile Include="Mapping\Dimension.cs" />
|
||||||
<Compile Include="Protocol\JwtPayloadDecode.cs" />
|
<Compile Include="Protocol\JwtPayloadDecode.cs" />
|
||||||
<Compile Include="Protocol\Handlers\PacketPalettes\PacketPalette118.cs" />
|
<Compile Include="Protocol\Handlers\PacketPalettes\PacketPalette118.cs" />
|
||||||
<Compile Include="Protocol\MojangAPI.cs" />
|
<Compile Include="Protocol\MojangAPI.cs" />
|
||||||
|
|
|
||||||
|
|
@ -302,17 +302,23 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
for (int i = 0; i < worldCount; i++)
|
for (int i = 0; i < worldCount; i++)
|
||||||
dataTypes.ReadNextString(packetData); // World Names - 1.16 and above
|
dataTypes.ReadNextString(packetData); // World Names - 1.16 and above
|
||||||
dataTypes.ReadNextNbt(packetData); // Dimension Codec - 1.16 and above
|
dataTypes.ReadNextNbt(packetData); // Dimension Codec - 1.16 and above
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Current dimension - String identifier in 1.16, varInt below 1.16, byte below 1.9.1
|
string currentDimensionName = null;
|
||||||
|
Dictionary<string, object> currentDimensionType = null;
|
||||||
|
|
||||||
|
// Current dimension
|
||||||
|
// NBT Tag Compound: 1.16.2 and above
|
||||||
|
// String identifier: 1.16 and 1.16.1
|
||||||
|
// varInt: [1.9.1 to 1.15.2]
|
||||||
|
// byte: below 1.9.1
|
||||||
if (protocolversion >= MC116Version)
|
if (protocolversion >= MC116Version)
|
||||||
{
|
{
|
||||||
if (protocolversion >= MC1162Version)
|
if (protocolversion >= MC1162Version)
|
||||||
dataTypes.ReadNextNbt(packetData);
|
currentDimensionType = dataTypes.ReadNextNbt(packetData);
|
||||||
else
|
else
|
||||||
dataTypes.ReadNextString(packetData);
|
dataTypes.ReadNextString(packetData);
|
||||||
// TODO handle dimensions for 1.16+, needed for terrain handling
|
|
||||||
// TODO this data give min and max y which will be needed for chunk collumn handling
|
|
||||||
this.currentDimension = 0;
|
this.currentDimension = 0;
|
||||||
}
|
}
|
||||||
else if (protocolversion >= MC191Version)
|
else if (protocolversion >= MC191Version)
|
||||||
|
|
@ -322,8 +328,16 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
|
|
||||||
if (protocolversion < MC114Version)
|
if (protocolversion < MC114Version)
|
||||||
dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below
|
dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below
|
||||||
|
|
||||||
if (protocolversion >= MC116Version)
|
if (protocolversion >= MC116Version)
|
||||||
dataTypes.ReadNextString(packetData); // World Name - 1.16 and above
|
currentDimensionName = dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above
|
||||||
|
|
||||||
|
if (protocolversion >= MC1162Version)
|
||||||
|
new Task(() =>
|
||||||
|
{
|
||||||
|
handler.GetWorld().SetDimension(currentDimensionName, currentDimensionType);
|
||||||
|
}).Start();
|
||||||
|
|
||||||
if (protocolversion >= MC115Version)
|
if (protocolversion >= MC115Version)
|
||||||
dataTypes.ReadNextLong(packetData); // Hashed world seed - 1.15 and above
|
dataTypes.ReadNextLong(packetData); // Hashed world seed - 1.15 and above
|
||||||
|
|
||||||
|
|
@ -362,11 +376,12 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
handler.OnTextReceived(message, true);
|
handler.OnTextReceived(message, true);
|
||||||
break;
|
break;
|
||||||
case PacketTypesIn.Respawn:
|
case PacketTypesIn.Respawn:
|
||||||
|
string dimensionNameInRespawn = null;
|
||||||
|
Dictionary<string, object> dimensionTypeInRespawn = null;
|
||||||
if (protocolversion >= MC116Version)
|
if (protocolversion >= MC116Version)
|
||||||
{
|
{
|
||||||
// TODO handle dimensions for 1.16+, needed for terrain handling
|
|
||||||
if (protocolversion >= MC1162Version)
|
if (protocolversion >= MC1162Version)
|
||||||
dataTypes.ReadNextNbt(packetData);
|
dimensionTypeInRespawn = dataTypes.ReadNextNbt(packetData);
|
||||||
else
|
else
|
||||||
dataTypes.ReadNextString(packetData);
|
dataTypes.ReadNextString(packetData);
|
||||||
this.currentDimension = 0;
|
this.currentDimension = 0;
|
||||||
|
|
@ -377,7 +392,14 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
this.currentDimension = dataTypes.ReadNextInt(packetData);
|
this.currentDimension = dataTypes.ReadNextInt(packetData);
|
||||||
}
|
}
|
||||||
if (protocolversion >= MC116Version)
|
if (protocolversion >= MC116Version)
|
||||||
dataTypes.ReadNextString(packetData); // World Name - 1.16 and above
|
dimensionNameInRespawn = dataTypes.ReadNextString(packetData); // World Name - 1.16 and above
|
||||||
|
|
||||||
|
if (protocolversion >= MC1162Version)
|
||||||
|
new Task(() =>
|
||||||
|
{
|
||||||
|
handler.GetWorld().SetDimension(dimensionNameInRespawn, dimensionTypeInRespawn);
|
||||||
|
}).Start();
|
||||||
|
|
||||||
if (protocolversion < MC114Version)
|
if (protocolversion < MC114Version)
|
||||||
dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below
|
dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below
|
||||||
if (protocolversion >= MC115Version)
|
if (protocolversion >= MC115Version)
|
||||||
|
|
@ -435,19 +457,26 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
int chunkZ = dataTypes.ReadNextInt(packetData);
|
int chunkZ = dataTypes.ReadNextInt(packetData);
|
||||||
if (protocolversion >= MC117Version)
|
if (protocolversion >= MC117Version)
|
||||||
{
|
{
|
||||||
ulong[] verticalStripBitmask = dataTypes.ReadNextULongArray(packetData); // Bit Mask Length and Primary Bit Mask
|
ulong[] verticalStripBitmask = null;
|
||||||
|
|
||||||
|
if (protocolversion == MC117Version || protocolversion == MC1171Version)
|
||||||
|
verticalStripBitmask = dataTypes.ReadNextULongArray(packetData); // Bit Mask Length and Primary Bit Mask
|
||||||
|
|
||||||
dataTypes.ReadNextNbt(packetData); // Heightmaps
|
dataTypes.ReadNextNbt(packetData); // Heightmaps
|
||||||
|
|
||||||
|
if (protocolversion == MC117Version || protocolversion == MC1171Version)
|
||||||
|
{
|
||||||
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
|
||||||
new Task(() =>
|
new Task(() =>
|
||||||
{
|
{
|
||||||
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, verticalStripBitmask, currentDimension, packetData);
|
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, verticalStripBitmask, packetData);
|
||||||
}).Start();
|
}).Start();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -600,10 +629,10 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
if (protocolversion >= MC1162Version)
|
if (protocolversion >= MC1162Version)
|
||||||
{
|
{
|
||||||
long chunkSection = dataTypes.ReadNextLong(packetData);
|
long chunkSection = dataTypes.ReadNextLong(packetData);
|
||||||
int sectionX = (int)(chunkSection >> 42);
|
int sectionX = (int)((chunkSection >> 42) & 0x3FFFFF);
|
||||||
int sectionY = (int)((chunkSection << 44) >> 44);
|
int sectionZ = (int)((chunkSection >> 20) & 0x3FFFFF);
|
||||||
int sectionZ = (int)((chunkSection << 22) >> 42);
|
int sectionY = (int)((chunkSection) & 0xFFFFF);
|
||||||
dataTypes.ReadNextBool(packetData); // Useless boolean
|
dataTypes.ReadNextBool(packetData); // Useless boolean (Related to light update)
|
||||||
int blocksSize = dataTypes.ReadNextVarInt(packetData);
|
int blocksSize = dataTypes.ReadNextVarInt(packetData);
|
||||||
for (int i = 0; i < blocksSize; i++)
|
for (int i = 0; i < blocksSize; i++)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -28,38 +28,27 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Process chunk column data from the server and (un)load the chunk from the Minecraft world - 1.17 and above
|
/// Reading the "Block states" field: consists of 4096 entries, representing all the blocks in the chunk section.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="chunkX">Chunk X location</param>
|
/// <param name="chunk">Blocks will store in this chunk</param>
|
||||||
/// <param name="chunkZ">Chunk Z location</param>
|
/// <param name="cache">Cache for reading data</param>
|
||||||
/// <param name="chunkMasks">Chunk mask for reading data, store in bitset</param>
|
private Chunk ReadBlockStatesField(ref Chunk chunk, Queue<byte> cache)
|
||||||
/// <param name="currentDimension">Current dimension type (0 = overworld)</param>
|
|
||||||
/// <param name="cache">Cache for reading chunk data</param>
|
|
||||||
public void ProcessChunkColumnData(int chunkX, int chunkZ, ulong[] chunkMasks, int currentDimension, Queue<byte> cache)
|
|
||||||
{
|
{
|
||||||
int chunkColumnSize = chunkMasks.Length * 64;
|
|
||||||
if (protocolversion >= Protocol18Handler.MC117Version)
|
|
||||||
{
|
|
||||||
// 1.17 and above chunk format
|
|
||||||
// Unloading chunks is handled by a separate packet
|
|
||||||
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
|
|
||||||
{
|
|
||||||
if ((chunkMasks[chunkY / 64] & (1UL << (chunkY % 64))) != 0)
|
|
||||||
{
|
|
||||||
// Non-air block count inside chunk section, for lighting purposes
|
|
||||||
int blockCnt = dataTypes.ReadNextShort(cache);
|
|
||||||
|
|
||||||
// read Block states (Type: Paletted Container)
|
// read Block states (Type: Paletted Container)
|
||||||
Chunk chunk = new Chunk();
|
|
||||||
|
|
||||||
byte bitsPerEntry = dataTypes.ReadNextByte(cache);
|
byte bitsPerEntry = dataTypes.ReadNextByte(cache);
|
||||||
|
|
||||||
|
// 1.18(1.18.1) add a pattle named "Single valued" to replace the vertical strip bitmask in the old
|
||||||
if (bitsPerEntry == 0 && protocolversion >= Protocol18Handler.MC1181Version)
|
if (bitsPerEntry == 0 && protocolversion >= Protocol18Handler.MC1181Version)
|
||||||
{
|
{
|
||||||
// Palettes: Single valued - 1.xx and above
|
// Palettes: Single valued - 1.18(1.18.1) and above
|
||||||
ushort value = (ushort)dataTypes.ReadNextVarInt(cache);
|
ushort value = (ushort)dataTypes.ReadNextVarInt(cache);
|
||||||
|
|
||||||
dataTypes.SkipNextVarInt(cache); // Data Array Length will be zero
|
dataTypes.SkipNextVarInt(cache); // Data Array Length will be zero
|
||||||
|
|
||||||
|
// Empty chunks will not be stored
|
||||||
|
if (new Block(value).Type == Material.Air)
|
||||||
|
return null;
|
||||||
|
|
||||||
for (int blockY = 0; blockY < Chunk.SizeY; blockY++)
|
for (int blockY = 0; blockY < Chunk.SizeY; blockY++)
|
||||||
{
|
{
|
||||||
for (int blockZ = 0; blockZ < Chunk.SizeZ; blockZ++)
|
for (int blockZ = 0; blockZ < Chunk.SizeZ; blockZ++)
|
||||||
|
|
@ -79,8 +68,8 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
// Indirect Mode: For block states with bits per entry <= 4, 4 bits are used to represent a block.
|
// Indirect Mode: For block states with bits per entry <= 4, 4 bits are used to represent a block.
|
||||||
if (bitsPerEntry < 4) bitsPerEntry = 4;
|
if (bitsPerEntry < 4) bitsPerEntry = 4;
|
||||||
|
|
||||||
// Direct Mode: Bit mask covering bitsPerBlock bits
|
// Direct Mode: Bit mask covering bitsPerEntry bits
|
||||||
// EG, if bitsPerBlock = 5, valueMask = 00011111 in binary
|
// EG, if bitsPerEntry = 5, valueMask = 00011111 in binary
|
||||||
uint valueMask = (uint)((1 << bitsPerEntry) - 1);
|
uint valueMask = (uint)((1 << bitsPerEntry) - 1);
|
||||||
|
|
||||||
int paletteLength = 0; // Assume zero when length is absent
|
int paletteLength = 0; // Assume zero when length is absent
|
||||||
|
|
@ -145,6 +134,44 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process chunk column data from the server and (un)load the chunk from the Minecraft world - 1.17 and above
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chunkX">Chunk X 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="cache">Cache for reading chunk data</param>
|
||||||
|
public void ProcessChunkColumnData(int chunkX, int chunkZ, ulong[] verticalStripBitmask, Queue<byte> cache)
|
||||||
|
{
|
||||||
|
var world = handler.GetWorld();
|
||||||
|
while (world.GetDimension() == null)
|
||||||
|
; // Dimension parsing unfinished
|
||||||
|
|
||||||
|
int chunkColumnSize = (world.GetDimension().height + 15) / 16;
|
||||||
|
|
||||||
|
if (protocolversion >= Protocol18Handler.MC117Version)
|
||||||
|
{
|
||||||
|
// 1.17 and above chunk format
|
||||||
|
// Unloading chunks is handled by a separate packet
|
||||||
|
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
if ((protocolversion >= Protocol18Handler.MC1181Version) ||
|
||||||
|
(((protocolversion == Protocol18Handler.MC117Version) ||
|
||||||
|
(protocolversion == Protocol18Handler.MC1171Version)) &&
|
||||||
|
((verticalStripBitmask[chunkY / 64] & (1UL << (chunkY % 64))) != 0)))
|
||||||
|
{
|
||||||
|
// Non-air block count inside chunk section, for lighting purposes
|
||||||
|
int blockCnt = dataTypes.ReadNextShort(cache);
|
||||||
|
|
||||||
|
// Read Block states (Type: Paletted Container)
|
||||||
|
Chunk chunk = new Chunk();
|
||||||
|
ReadBlockStatesField(ref chunk, cache);
|
||||||
|
|
||||||
//We have our chunk, save the chunk into the world
|
//We have our chunk, save the chunk into the world
|
||||||
handler.InvokeOnMainThread(() =>
|
handler.InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
|
|
@ -153,11 +180,11 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
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
|
||||||
if (protocolversion >= Protocol18Handler.MC1181Version)
|
if (protocolversion >= Protocol18Handler.MC1181Version)
|
||||||
{
|
{
|
||||||
// skip read Biomes (Type: Paletted Container)
|
|
||||||
byte bitsPerEntryBiome = dataTypes.ReadNextByte(cache); // Bits Per Entry
|
byte bitsPerEntryBiome = dataTypes.ReadNextByte(cache); // Bits Per Entry
|
||||||
if (bitsPerEntryBiome == 0 && protocolversion >= Protocol18Handler.MC1181Version)
|
if (bitsPerEntryBiome == 0)
|
||||||
{
|
{
|
||||||
dataTypes.SkipNextVarInt(cache); // Value
|
dataTypes.SkipNextVarInt(cache); // Value
|
||||||
dataTypes.SkipNextVarInt(cache); // Data Array Length
|
dataTypes.SkipNextVarInt(cache); // Data Array Length
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue