mirror of
https://gitea.tendokyu.moe/ppc/amnet.git
synced 2026-09-22 22:28:22 +03:00
92 lines
2.8 KiB
C#
92 lines
2.8 KiB
C#
using System;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
|
|
namespace AMNet.Server;
|
|
|
|
/// <summary>
|
|
/// Represents a storage location to load/read cards from
|
|
/// </summary>
|
|
internal class CardPresenter
|
|
{
|
|
private readonly Lock _cardLock = new();
|
|
private StoredCard _currentCard;
|
|
|
|
public record StoredCard(byte[] AccessCode, byte[] IDm, long ExpiresAt)
|
|
{
|
|
public bool Expired => Environment.TickCount64 >= ExpiresAt;
|
|
|
|
public override string ToString() => FormatHexCode(AccessCode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the currently active card without clearing it
|
|
/// </summary>
|
|
public StoredCard PeekActiveCard()
|
|
{
|
|
lock (_cardLock)
|
|
{
|
|
return _currentCard;
|
|
}
|
|
}
|
|
|
|
public StoredCard TakeActiveCard(bool? requireIDm = null)
|
|
{
|
|
lock (_cardLock)
|
|
{
|
|
// IDm and requireIDm are mutually exclusive
|
|
if (_currentCard == null || (requireIDm.HasValue && (_currentCard.IDm != null) ^ requireIDm.Value))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var card = _currentCard;
|
|
_currentCard = null;
|
|
|
|
return card;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the card
|
|
/// </summary>
|
|
/// <param name="accessCode">The access code of the card to use</param>
|
|
/// <param name="idmHex">The FeliCa card IDm, if a physical card was used</param>
|
|
/// <param name="validFor">How long the card should be presented to the game for in milliseconds</param>
|
|
/// <returns>Whether the card was set successfully</returns>
|
|
public StoredCard SetCard(string accessCode, string idmHex, long validFor = 5000)
|
|
{
|
|
// ensure the matrix code is 20-digits long, otherwise pad with zeros
|
|
var matrixCode = accessCode.Replace(" ", "").PadLeft(20, '0');
|
|
var bytes = new byte[10];
|
|
|
|
for (var i = 0; i < bytes.Length; i++)
|
|
{
|
|
var value = matrixCode.Substring(i * 2, 2);
|
|
if (byte.TryParse(value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var b))
|
|
{
|
|
bytes[i] = b;
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
var idmBytes = !string.IsNullOrWhiteSpace(idmHex) && idmHex.Length <= 16 && idmHex.All(char.IsAsciiHexDigit) ? Convert.FromHexString(idmHex.PadLeft(16, '0')) : null;
|
|
var card = new StoredCard(bytes, idmBytes, Environment.TickCount64 + validFor);
|
|
|
|
lock (_cardLock)
|
|
{
|
|
_currentCard = card;
|
|
}
|
|
|
|
return card;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Formats a byte array as a hex string, inserting a space every 2 characters
|
|
/// </summary>
|
|
public static string FormatHexCode(byte[] code) => string.Join(" ", code.Chunk(2).Select(Convert.ToHexString));
|
|
} |