Skip to content

Commit 17c941c

Browse files
committed
Fix some issues related to chunk loading
1 parent 83749f3 commit 17c941c

File tree

8 files changed

+161
-142
lines changed

8 files changed

+161
-142
lines changed

src/Alex/Alex.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
<ItemGroup>
9494
<PackageReference Include="CommandLineParser" Version="2.9.0-preview1" />
9595
<PackageReference Include="ConcurrentHashSet" Version="1.3.0" />
96+
<PackageReference Include="ConcurrentObservableCollections" Version="1.1.9" />
9697
<PackageReference Include="DiscordRichPresence" Version="1.0.175" />
9798
<PackageReference Include="EasyPipes" Version="1.3.0" />
9899
<PackageReference Include="FmodAudio" Version="2.2.5" />

src/Alex/Utils/Auth/AuthResponse.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ namespace Alex.Utils.Auth
55
{
66
public class AuthResponse<TClaims>
77
{
8+
[JsonIgnore] public bool Error { get; set; }
9+
[JsonIgnore] public int StatusCode { get; set; }
810
[JsonProperty("IssueInstant")] public DateTimeOffset IssueInstant { get; set; }
911

1012
[JsonProperty("NotAfter")] public DateTimeOffset NotAfter { get; set; }

src/Alex/Utils/Auth/MojangApi.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,27 @@ private static async Task<MojangAuthResponse> ExchangeLiveForXbox(BedrockTokenPa
231231
{
232232
HttpClient client = _httpClient;
233233
var xblResponse = await _xboxAuth.AuthenticateWithXBL(client, token.AccessToken);
234+
235+
if (xblResponse.Error)
236+
{
237+
return new MojangAuthResponse(MojangAuthResult.BadRequest)
238+
{
239+
ErrorMessage = "Invalid credentials...", StatusCode = (int)xblResponse.StatusCode
240+
};
241+
}
242+
234243
var xblToken = xblResponse.Token;
235244
var userHash = xblResponse.DisplayClaims.Xui[0].Uhs;
236245

237246
var xsts = await _xboxAuth.AuthenticatewithJavaXSTS(client, xblToken);
238-
247+
if (xsts.Error)
248+
{
249+
return new MojangAuthResponse(MojangAuthResult.BadRequest)
250+
{
251+
ErrorMessage = "Invalid credentials...", StatusCode = (int)xsts.StatusCode
252+
};
253+
}
254+
239255
userHash = xsts.DisplayClaims.Xui[0].UserHash;
240256
var xstsToken = xsts.Token;
241257
var rawLoginResult = await _xboxAuth.AuthenticateWithMinecraft(client, userHash, xstsToken);

src/Alex/Utils/Auth/XboxAuthService.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,12 @@ public async Task<AuthResponse<XuiDisplayClaims<XstsXui>>> AuthenticatewithJavaX
274274
using (var response = await client.SendAsync(r, HttpCompletionOption.ResponseContentRead)
275275
.ConfigureAwait(false))
276276
{
277-
response.EnsureSuccessStatusCode();
277+
if (!response.IsSuccessStatusCode)
278+
return new AuthResponse<XuiDisplayClaims<XstsXui>>()
279+
{
280+
Error = true,
281+
StatusCode = (int) response.StatusCode
282+
};
278283

279284
var rawResponse = await response.Content.ReadAsStringAsync();
280285

@@ -426,7 +431,12 @@ public async Task<AuthResponse<XuiDisplayClaims<Xui>>> AuthenticateWithXBL(HttpC
426431
using (var response = await client.SendAsync(r, HttpCompletionOption.ResponseContentRead)
427432
.ConfigureAwait(false))
428433
{
429-
response.EnsureSuccessStatusCode();
434+
if (!response.IsSuccessStatusCode)
435+
return new AuthResponse<XuiDisplayClaims<Xui>>()
436+
{
437+
Error = true,
438+
StatusCode = (int) response.StatusCode
439+
};
430440

431441
return JsonConvert.DeserializeObject<AuthResponse<XuiDisplayClaims<Xui>>>(
432442
await response.Content.ReadAsStringAsync());

src/Alex/Worlds/ChunkManager.cs

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ public class ChunkManager : IDisposable, ITicked
9494
private ActionBlock<ChunkUpdateData> _actionBlock;
9595
private PriorityBufferBlock<ChunkUpdateData> _priorityBuffer;
9696
private List<ChunkCoordinates> _queued = new List<ChunkCoordinates>();
97-
97+
private object _queuedLock = new object();
98+
9899
public bool CalculateSkyLighting { get; set; } = true;
99100
public bool CalculateBlockLighting { get; set; } = true;
100101

@@ -111,20 +112,9 @@ public ChunkManager(IServiceProvider serviceProvider,
111112
Options = serviceProvider.GetRequiredService<IOptionsProvider>().AlexOptions;
112113

113114
_resourceManager = serviceProvider.GetRequiredService<ResourceManager>();
114-
//var stillAtlas = serviceProvider.GetRequiredService<ResourceManager>().BlockAtlas.GetAtlas();
115115

116116
//var fogStart = 0;
117117
Shaders = new RenderingShaders();
118-
//Shaders.SetTextures(stillAtlas);
119-
/*FogEnabled = Options.VideoOptions.Fog.Value;
120-
FogDistance = Options.VideoOptions.RenderDistance.Value;
121-
Options.VideoOptions.Fog.Bind(
122-
(old, newValue) =>
123-
{
124-
FogEnabled = newValue;
125-
FogDistance = RenderDistance;
126-
});*/
127-
//_renderSampler.MaxMipLevel = stillAtlas.LevelCount;
128118

129119
Chunks = new ConcurrentDictionary<ChunkCoordinates, ChunkColumn>();
130120
CancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
@@ -197,7 +187,7 @@ private void BuildActionBlock(int threads)
197187
{
198188
CancellationToken = CancellationToken.Token,
199189
EnsureOrdered = false,
200-
MaxDegreeOfParallelism = Math.Max(threads / 3, 1),
190+
MaxDegreeOfParallelism = 1,
201191
NameFormat = "Chunk Builder: {0}-{1}"
202192
};
203193

@@ -332,16 +322,31 @@ public void EnsureStarted()
332322
_processingThread = task;
333323
}
334324

325+
326+
private bool IsQueued(ChunkCoordinates coordinates)
327+
{
328+
lock (_queuedLock)
329+
return _queued.Contains(coordinates);
330+
}
331+
332+
private void RemoveQueued(ChunkCoordinates coordinates)
333+
{
334+
lock (_queuedLock)
335+
{
336+
_queued.Remove(coordinates);
337+
}
338+
}
339+
335340
private void DoUpdate(ChunkUpdateData data)
336341
{
337342
Interlocked.Increment(ref _threadsRunning);
338343

339344
try
340345
{
341-
if (!TryGetChunk(data.Coordinates, out var chunk) || !chunk.Scheduled) return;
342-
343-
if (!Monitor.TryEnter(chunk.UpdateLock, 0))
346+
if (!TryGetChunk(data.Coordinates, out var chunk) || !chunk.Semaphore.Wait(0))
347+
{
344348
return;
349+
}
345350

346351
Stopwatch timingWatch = Stopwatch.StartNew();
347352

@@ -358,24 +363,20 @@ private void DoUpdate(ChunkUpdateData data)
358363
chunk.CalculateLighting = false;
359364
}
360365

361-
//using (var ba = new CachedBlockAccess(World))
362-
//{
363-
if (chunk.UpdateBuffer(World, true))
364-
{
365-
chunk.Scheduled = false;
366-
OnChunkUpdate?.Invoke(this, new ChunkUpdatedEventArgs(chunk, timingWatch.Elapsed));
367-
}
368-
//}
366+
if (chunk.UpdateBuffer(World, true))
367+
{
368+
OnChunkUpdate?.Invoke(this, new ChunkUpdatedEventArgs(chunk, timingWatch.Elapsed));
369+
}
369370
}
370371
finally
371372
{
372-
_queued.Remove(data.Coordinates);
373373
//chunk.Scheduled = false;
374-
Monitor.Exit(chunk.UpdateLock);
374+
chunk.Semaphore.Release();
375375
}
376376
}
377377
finally
378378
{
379+
RemoveQueued(data.Coordinates);
379380
Interlocked.Decrement(ref _threadsRunning);
380381
}
381382
}
@@ -416,7 +417,8 @@ public void AddChunk(ChunkColumn chunk, ChunkCoordinates position, bool doUpdate
416417

417418
private void OnRemoveChunk(ChunkColumn column, bool dispose)
418419
{
419-
_queued?.Remove(new ChunkCoordinates(column.X, column.Z));
420+
RemoveQueued(new ChunkCoordinates(column.X, column.Z));
421+
420422
OnChunkRemoved?.Invoke(this, new ChunkRemovedEventArgs(column));
421423

422424
if (dispose)
@@ -464,30 +466,36 @@ public void ScheduleChunkUpdate(ChunkCoordinates position,
464466
{
465467
if (!Chunks.TryGetValue(position, out var cc)) return;
466468

467-
if (cc.Scheduled && !prioritize)
469+
if (IsQueued(position) || !Monitor.TryEnter(cc.QueueLock, 0))
468470
return;
469-
470-
cc.Scheduled = true;
471-
472-
//if (!cc.Neighboring.Contains(source))
473-
// cc.Neighboring.Add(source);
474-
475-
Priority priority = Priority.Medium;
476-
477-
if (prioritize)
471+
472+
lock (_queuedLock)
478473
{
479-
priority = Priority.High;
474+
if (!_queued.Contains(position))
475+
{
476+
_queued.Add(position);
477+
}
480478
}
481-
else if ((type & ScheduleType.Border) != 0)
479+
480+
try
482481
{
483-
priority = Priority.Low;
484-
}
482+
Priority priority = Priority.Medium;
485483

486-
if (!_queued.Contains(position))
487-
{
488-
_queued.Add(position);
484+
if (prioritize)
485+
{
486+
priority = Priority.High;
487+
}
488+
else if ((type & ScheduleType.Border) != 0)
489+
{
490+
priority = Priority.Low;
491+
}
492+
489493
_priorityBuffer.Post(new ChunkUpdateData(position, type, source), priority);
490494
}
495+
finally
496+
{
497+
Monitor.Exit(cc.QueueLock);
498+
}
491499
}
492500

493501
#region Drawing
@@ -688,7 +696,7 @@ public void OnTick()
688696

689697
if (inView && index + 1 < max)
690698
{
691-
if (chunk.Value.IsNew && !chunk.Value.Scheduled)
699+
if (chunk.Value.IsNew)
692700
{
693701
ScheduleChunkUpdate(chunk.Key, ScheduleType.Full);
694702
}

src/Alex/Worlds/Chunks/ChunkColumn.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ public class ChunkColumn
3434
// private readonly int[] _biomeId;
3535
private readonly short[] _height = new short[256];
3636

37-
public object UpdateLock { get; set; } = new object();
37+
//public object UpdateLock { get; set; } = new object();
38+
public readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
39+
private readonly SemaphoreSlim DataSemaphore = new SemaphoreSlim(1);
3840

41+
public object QueueLock = new object();
3942
public ConcurrentDictionary<BlockCoordinates, NbtCompound> BlockEntities { get; }
4043
//public NbtCompound[] GetBlockEntities => BlockEntities.ToArray();
4144

@@ -54,7 +57,6 @@ private set
5457
}
5558
}
5659

57-
private object _dataLock = new object();
5860
public WorldSettings WorldSettings { get; }
5961
protected readonly int _sectionOffset;
6062
private ChunkData _chunkData;
@@ -130,13 +132,12 @@ protected void SetScheduled(int x, int y, int z, bool value)
130132
public static float AverageUpdateTime => MovingAverage.Average;
131133
public static float MaxUpdateTime => MovingAverage.Maximum;
132134
public static float MinUpdateTime => MovingAverage.Minimum;
133-
public bool Scheduled { get; set; } = false;
134135

135136
private static readonly MovingAverage MovingAverage = new MovingAverage();
136137

137138
public bool UpdateBuffer(IBlockAccess world, bool applyChanges)
138139
{
139-
if (!Monitor.TryEnter(_dataLock, 0))
140+
if (!DataSemaphore.Wait(0))
140141
return false;
141142

142143
Stopwatch time = Stopwatch.StartNew();
@@ -219,7 +220,7 @@ public bool UpdateBuffer(IBlockAccess world, bool applyChanges)
219220
}
220221
finally
221222
{
222-
Monitor.Exit(_dataLock);
223+
DataSemaphore.Release();
223224
time.Stop();
224225

225226
MovingAverage.ComputeAverage((float)time.Elapsed.TotalMilliseconds);
@@ -608,7 +609,6 @@ public bool RemoveBlockEntity(BlockCoordinates coordinates)
608609
return BlockEntities.TryRemove(coordinates, out _);
609610
}
610611

611-
public List<ChunkCoordinates> Neighboring = new List<ChunkCoordinates>();
612612
private bool _disposed = false;
613613

614614
private void Dispose(bool disposing)

0 commit comments

Comments
 (0)