Change how world is stored & Bug fix

This commit is contained in:
BruceChen 2022-08-31 18:00:00 +08:00
parent c90ea0e92b
commit 9089bb4cdb
4 changed files with 21 additions and 98 deletions

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -13,19 +14,15 @@ namespace MinecraftClient.Mapping
{ {
/// <summary> /// <summary>
/// The chunks contained into the Minecraft world /// The chunks contained into the Minecraft world
/// Tuple<int, int>: Tuple<chunkX, chunkZ>
/// </summary> /// </summary>
private Dictionary<int, Dictionary<int, ChunkColumn>> chunks = new(); private ConcurrentDictionary<Tuple<int, int>, ChunkColumn> chunks = new();
/// <summary> /// <summary>
/// The dimension info of the world /// The dimension info of the world
/// </summary> /// </summary>
private static Dimension dimension = new(); private static Dimension dimension = new();
/// <summary>
/// Lock for thread safety
/// </summary>
private readonly ReaderWriterLockSlim chunksLock = new();
/// <summary> /// <summary>
/// Chunk data parsing progress /// Chunk data parsing progress
/// </summary> /// </summary>
@ -42,50 +39,16 @@ namespace MinecraftClient.Mapping
{ {
get get
{ {
chunksLock.EnterReadLock(); chunks.TryGetValue(new(chunkX, chunkZ), out ChunkColumn? chunkColumn);
try return chunkColumn;
{
//Read a chunk
if (chunks.ContainsKey(chunkX))
if (chunks[chunkX].ContainsKey(chunkZ))
return chunks[chunkX][chunkZ];
return null;
}
finally
{
chunksLock.ExitReadLock();
}
} }
set set
{ {
chunksLock.EnterWriteLock(); Tuple<int, int> chunkCoord = new(chunkX, chunkZ);
try if (value == null)
{ chunks.Remove(chunkCoord, out _);
if (value != null)
{
//Update a chunk column
if (!chunks.ContainsKey(chunkX))
chunks[chunkX] = new Dictionary<int, ChunkColumn>();
chunks[chunkX][chunkZ] = value;
}
else else
{ chunks.AddOrUpdate(chunkCoord, value, (_, _) => value);
//Unload a chunk column
if (chunks.ContainsKey(chunkX))
{
if (chunks[chunkX].ContainsKey(chunkZ))
{
chunks[chunkX].Remove(chunkZ);
if (chunks[chunkX].Count == 0)
chunks.Remove(chunkX);
}
}
}
}
finally
{
chunksLock.ExitWriteLock();
}
} }
} }
@ -120,36 +83,7 @@ namespace MinecraftClient.Mapping
/// <param name="loadCompleted">Whether the ChunkColumn has been fully loaded</param> /// <param name="loadCompleted">Whether the ChunkColumn has been fully loaded</param>
public void StoreChunk(int chunkX, int chunkY, int chunkZ, int chunkColumnSize, Chunk? chunk, bool loadCompleted) public void StoreChunk(int chunkX, int chunkY, int chunkZ, int chunkColumnSize, Chunk? chunk, bool loadCompleted)
{ {
ChunkColumn? chunkColumn = null; ChunkColumn chunkColumn = chunks.GetOrAdd(new(chunkX, chunkZ), (_) => new(chunkColumnSize));
chunksLock.EnterUpgradeableReadLock();
try
{
//Read a chunk
if (chunks.ContainsKey(chunkX))
if (chunks[chunkX].ContainsKey(chunkZ))
chunkColumn = chunks[chunkX][chunkZ];
if (chunkColumn == null)
{
chunkColumn = new ChunkColumn(chunkColumnSize);
chunksLock.EnterWriteLock();
try
{
//Update a chunk column
if (!chunks.ContainsKey(chunkX))
chunks[chunkX] = new Dictionary<int, ChunkColumn>();
chunks[chunkX][chunkZ] = chunkColumn;
}
finally
{
chunksLock.ExitWriteLock();
}
}
}
finally
{
chunksLock.ExitUpgradeableReadLock();
}
chunkColumn[chunkY] = chunk; chunkColumn[chunkY] = chunk;
if (loadCompleted) if (loadCompleted)
chunkColumn.FullyLoaded = true; chunkColumn.FullyLoaded = true;
@ -249,18 +183,10 @@ namespace MinecraftClient.Mapping
/// </summary> /// </summary>
public void Clear() public void Clear()
{ {
chunksLock.EnterWriteLock(); chunks = new();
try
{
chunks = new Dictionary<int, Dictionary<int, ChunkColumn>>();
chunkCnt = 0; chunkCnt = 0;
chunkLoadNotCompleted = 0; chunkLoadNotCompleted = 0;
} }
finally
{
chunksLock.ExitWriteLock();
}
}
/// <summary> /// <summary>
/// Get the location of block of the entity is looking /// Get the location of block of the entity is looking

View file

@ -712,10 +712,10 @@ namespace MinecraftClient
try try
{ {
Command cmd = (Command)Activator.CreateInstance(type); Command cmd = (Command)Activator.CreateInstance(type);
cmds[cmd.CmdName.ToLower()] = cmd; cmds[Settings.ToLowerIfNeed(cmd.CmdName)] = cmd;
cmd_names.Add(cmd.CmdName.ToLower()); cmd_names.Add(Settings.ToLowerIfNeed(cmd.CmdName));
foreach (string alias in cmd.getCMDAliases()) foreach (string alias in cmd.getCMDAliases())
cmds[alias.ToLower()] = cmd; cmds[Settings.ToLowerIfNeed(alias)] = cmd;
} }
catch (Exception e) catch (Exception e)
{ {

View file

@ -71,14 +71,11 @@ 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;
int entryPerLong = 64 / bitsPerEntry; // entryPerLong = sizeof(long) / bitsPerEntry
// Direct Mode: Bit mask covering bitsPerEntry bits // Direct Mode: Bit mask covering bitsPerEntry bits
// EG, if bitsPerEntry = 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 = usePalette ? dataTypes.ReadNextVarInt(cache) : 0; // Assume zero when length is absent
if (usePalette) paletteLength = dataTypes.ReadNextVarInt(cache);
Span<uint> palette = paletteLength < 256 ? stackalloc uint[paletteLength] : new uint[paletteLength]; Span<uint> palette = paletteLength < 256 ? stackalloc uint[paletteLength] : new uint[paletteLength];
for (int i = 0; i < paletteLength; i++) for (int i = 0; i < paletteLength; i++)

View file

@ -14,14 +14,14 @@ namespace MinecraftClient.Protocol.Keys
public DateTime RefreshedAfter; // Todo: add a timer public DateTime RefreshedAfter; // Todo: add a timer
private const string DataTimeFormat = "O"; private const string DataTimeFormat = "yyyy-MM-ddTHH:mm:ss.ffffffZ";
public PlayerKeyPair(PublicKey keyPublic, PrivateKey keyPrivate, string expiresAt, string refreshedAfter) public PlayerKeyPair(PublicKey keyPublic, PrivateKey keyPrivate, string expiresAt, string refreshedAfter)
{ {
PublicKey = keyPublic; PublicKey = keyPublic;
PrivateKey = keyPrivate; PrivateKey = keyPrivate;
ExpiresAt = DateTime.ParseExact(expiresAt, "yyyy-MM-ddTHH:mm:ss.fffffffZ", System.Globalization.CultureInfo.InvariantCulture).ToUniversalTime(); ExpiresAt = DateTime.ParseExact(expiresAt, DataTimeFormat, System.Globalization.CultureInfo.InvariantCulture).ToUniversalTime();
RefreshedAfter = DateTime.ParseExact(refreshedAfter, "yyyy-MM-ddTHH:mm:ss.fffffffZ", System.Globalization.CultureInfo.InvariantCulture).ToUniversalTime(); RefreshedAfter = DateTime.ParseExact(refreshedAfter, DataTimeFormat, System.Globalization.CultureInfo.InvariantCulture).ToUniversalTime();
} }
public bool NeedRefresh() public bool NeedRefresh()