-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGameCodeManager.cs
138 lines (105 loc) · 4.42 KB
/
GameCodeManager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using System;
using System.IO;
using System.Linq;
using Impostor.Api.Games;
using Boot.Codes.Handlers;
using System.Collections.Generic;
using Impostor.Api.Events.Managers;
using Microsoft.Extensions.Logging;
using System.Security.Cryptography;
namespace Boot.Codes
{
public class GameCodeManager : IGameCodeManager
{
private static readonly HashSet<char> V2Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToHashSet();
private readonly List<GameCode> _codes;
private readonly HashSet<GameCode> _inUse;
private readonly object _sync = new object();
private readonly ILogger<IGameCodeManager> _logger;
private readonly IGameCodeFactory _codeFactory;
public string Path => System.IO.Path.GetFullPath("Boot.Codes");
public int SixCharCodes { get; }
public int FourCharCodes { get; }
public GameCodeManager(ILogger<GameCodeManager> logger, IGameCodeFactory codeFactory, IEventManager eventManager)
{
this._logger = logger;
this._codeFactory = codeFactory;
logger.LogInformation("Boot.Codes: Reading files from {Path}", Path);
var validCodes = Read().ToList();
if (validCodes.Count == 0) return;
validCodes.Shuffle();
this.FourCharCodes = validCodes.Count(code => code.Code.Length == 4);
this.SixCharCodes = validCodes.Count(code => code.Code.Length == 6);
this._codes = validCodes;
this._inUse = new HashSet<GameCode>();
eventManager.RegisterListener(new GameEventListener(this));
}
private IEnumerable<GameCode> Read()
{
var dirInfo = new DirectoryInfo(Path);
if (!dirInfo.Exists)
{
dirInfo.Create();
goto fail;
}
var comment = new[] { "--" };
var codes = new HashSet<GameCode>();
const StringSplitOptions splitOptions = StringSplitOptions.None;
var startTime = DateTime.Now;
var invalid = 0;
foreach (var file in dirInfo.GetFiles())
{
_logger.LogInformation("Boot.Codes: reading \"{Name}\"", file.Name);
foreach (var line in File.ReadLines(file.FullName))
{
if(string.IsNullOrWhiteSpace(line)) continue;
var trimStart = line.TrimStart();
if(trimStart.StartsWith(comment[0])) continue;
var codeStr = trimStart.Split(comment, 2, splitOptions)[0].TrimEnd();
if (codeStr.Length != 6 && codeStr.Length != 4 || codeStr.Any(c=>!V2Chars.Contains(c)))
{
if (invalid++ < 5) _logger.LogWarning("Boot.Codes: The code \"{code}\" is invalid!", codeStr);
if (invalid == 6) _logger.LogWarning("Boot.Codes: Found more invalid codes, please check your input files and clean them up");
continue;
}
var code = new GameCode(codeStr);
if (!code.IsInvalid && !codes.Contains(code)) codes.Add(code);
else invalid++;
}
}
if (codes.Count == 0) goto fail;
_logger.LogInformation("Boot.Codes: Finished loading files in {Seconds} seconds, with {invalids} invalid codes.", (DateTime.Now - startTime).Seconds, invalid);
return codes;
fail:
{
_logger.LogWarning("Boot.Codes: No valid word list found.");
return Enumerable.Empty<GameCode>();
}
}
public GameCode Get()
{
lock (_sync)
{
if (_codes.Count == 0)
{
_logger.LogWarning("Boot.Codes: Ran out of codes!");
return _codeFactory.Create();
}
var index = RandomNumberGenerator.GetInt32(0, _codes.Count);
var code = _codes[index];
_codes.RemoveAt(index);
_inUse.Add(code);
return code;
}
}
public void Release(GameCode code)
{
lock (_sync)
{
if (!_inUse.Contains(code)) return; // generated by the factory
_inUse.Remove(code);
_codes.Add(code);
}
}
}
}