Skip to content

Commit aeca6a8

Browse files
committed
Add thead safety to terrain data (#1999)
Allow safely reading terrain data from other threads
1 parent d6220ff commit aeca6a8

File tree

3 files changed

+101
-25
lines changed

3 files changed

+101
-25
lines changed

MinecraftClient/Mapping/Chunk.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Text;
5+
using System.Threading;
56

67
namespace MinecraftClient.Mapping
78
{
@@ -19,6 +20,11 @@ public class Chunk
1920
/// </summary>
2021
private readonly Block[,,] blocks = new Block[SizeX, SizeY, SizeZ];
2122

23+
/// <summary>
24+
/// Lock for thread safety
25+
/// </summary>
26+
private readonly ReaderWriterLockSlim blockLock = new ReaderWriterLockSlim();
27+
2228
/// <summary>
2329
/// Read, or set the specified block
2430
/// </summary>
@@ -36,7 +42,16 @@ public class Chunk
3642
throw new ArgumentOutOfRangeException("blockY", "Must be between 0 and " + (SizeY - 1) + " (inclusive)");
3743
if (blockZ < 0 || blockZ >= SizeZ)
3844
throw new ArgumentOutOfRangeException("blockZ", "Must be between 0 and " + (SizeZ - 1) + " (inclusive)");
39-
return blocks[blockX, blockY, blockZ];
45+
46+
blockLock.EnterReadLock();
47+
try
48+
{
49+
return blocks[blockX, blockY, blockZ];
50+
}
51+
finally
52+
{
53+
blockLock.ExitReadLock();
54+
}
4055
}
4156
set
4257
{
@@ -46,7 +61,16 @@ public class Chunk
4661
throw new ArgumentOutOfRangeException("blockY", "Must be between 0 and " + (SizeY - 1) + " (inclusive)");
4762
if (blockZ < 0 || blockZ >= SizeZ)
4863
throw new ArgumentOutOfRangeException("blockZ", "Must be between 0 and " + (SizeZ - 1) + " (inclusive)");
49-
blocks[blockX, blockY, blockZ] = value;
64+
65+
blockLock.EnterWriteLock();
66+
try
67+
{
68+
blocks[blockX, blockY, blockZ] = value;
69+
}
70+
finally
71+
{
72+
blockLock.ExitWriteLock();
73+
}
5074
}
5175
}
5276

MinecraftClient/Mapping/ChunkColumn.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Text;
5+
using System.Threading;
56

67
namespace MinecraftClient.Mapping
78
{
@@ -17,6 +18,11 @@ public class ChunkColumn
1718
/// </summary>
1819
private readonly Chunk[] chunks = new Chunk[ColumnSize];
1920

21+
/// <summary>
22+
/// Lock for thread safety
23+
/// </summary>
24+
private readonly ReaderWriterLockSlim chunkLock = new ReaderWriterLockSlim();
25+
2026
/// <summary>
2127
/// Get or set the specified chunk column
2228
/// </summary>
@@ -27,11 +33,27 @@ public Chunk this[int chunkY]
2733
{
2834
get
2935
{
30-
return chunks[chunkY];
36+
chunkLock.EnterReadLock();
37+
try
38+
{
39+
return chunks[chunkY];
40+
}
41+
finally
42+
{
43+
chunkLock.ExitReadLock();
44+
}
3145
}
3246
set
3347
{
34-
chunks[chunkY] = value;
48+
chunkLock.EnterWriteLock();
49+
try
50+
{
51+
chunks[chunkY] = value;
52+
}
53+
finally
54+
{
55+
chunkLock.ExitWriteLock();
56+
}
3557
}
3658
}
3759

MinecraftClient/Mapping/World.cs

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Text;
5+
using System.Threading;
56

67
namespace MinecraftClient.Mapping
78
{
@@ -15,6 +16,11 @@ public class World
1516
/// </summary>
1617
private Dictionary<int, Dictionary<int, ChunkColumn>> chunks = new Dictionary<int, Dictionary<int, ChunkColumn>>();
1718

19+
/// <summary>
20+
/// Lock for thread safety
21+
/// </summary>
22+
private readonly ReaderWriterLockSlim chunksLock = new ReaderWriterLockSlim();
23+
1824
/// <summary>
1925
/// Read, set or unload the specified chunk column
2026
/// </summary>
@@ -25,34 +31,50 @@ public class World
2531
{
2632
get
2733
{
28-
//Read a chunk
29-
if (chunks.ContainsKey(chunkX))
30-
if (chunks[chunkX].ContainsKey(chunkZ))
31-
return chunks[chunkX][chunkZ];
32-
return null;
34+
chunksLock.EnterReadLock();
35+
try
36+
{
37+
//Read a chunk
38+
if (chunks.ContainsKey(chunkX))
39+
if (chunks[chunkX].ContainsKey(chunkZ))
40+
return chunks[chunkX][chunkZ];
41+
return null;
42+
}
43+
finally
44+
{
45+
chunksLock.ExitReadLock();
46+
}
3347
}
3448
set
3549
{
36-
if (value != null)
37-
{
38-
//Update a chunk column
39-
if (!chunks.ContainsKey(chunkX))
40-
chunks[chunkX] = new Dictionary<int, ChunkColumn>();
41-
chunks[chunkX][chunkZ] = value;
42-
}
43-
else
50+
chunksLock.EnterWriteLock();
51+
try
4452
{
45-
//Unload a chunk column
46-
if (chunks.ContainsKey(chunkX))
53+
if (value != null)
4754
{
48-
if (chunks[chunkX].ContainsKey(chunkZ))
55+
//Update a chunk column
56+
if (!chunks.ContainsKey(chunkX))
57+
chunks[chunkX] = new Dictionary<int, ChunkColumn>();
58+
chunks[chunkX][chunkZ] = value;
59+
}
60+
else
61+
{
62+
//Unload a chunk column
63+
if (chunks.ContainsKey(chunkX))
4964
{
50-
chunks[chunkX].Remove(chunkZ);
51-
if (chunks[chunkX].Count == 0)
52-
chunks.Remove(chunkX);
65+
if (chunks[chunkX].ContainsKey(chunkZ))
66+
{
67+
chunks[chunkX].Remove(chunkZ);
68+
if (chunks[chunkX].Count == 0)
69+
chunks.Remove(chunkX);
70+
}
5371
}
5472
}
5573
}
74+
finally
75+
{
76+
chunksLock.ExitWriteLock();
77+
}
5678
}
5779
}
5880

@@ -117,7 +139,7 @@ public List<Location> FindBlock(Location from, Material block, int radiusx, int
117139
{
118140
Location doneloc = new Location(x, y, z);
119141
Block doneblock = GetBlock(doneloc);
120-
Material blockType = GetBlock(doneloc).Type;
142+
Material blockType = doneblock.Type;
121143
if (blockType == block)
122144
{
123145
list.Add(doneloc);
@@ -150,7 +172,15 @@ public void SetBlock(Location location, Block block)
150172
/// </summary>
151173
public void Clear()
152174
{
153-
chunks = new Dictionary<int, Dictionary<int, ChunkColumn>>();
175+
chunksLock.EnterWriteLock();
176+
try
177+
{
178+
chunks = new Dictionary<int, Dictionary<int, ChunkColumn>>();
179+
}
180+
finally
181+
{
182+
chunksLock.ExitWriteLock();
183+
}
154184
}
155185

156186
/// <summary>

0 commit comments

Comments
 (0)