Files
2026-10-16 23:33:13 -07:00

236 lines
6.6 KiB
C#

using System.Text.Json;
using RadicadeServer.DB;
namespace RadicadeServer.RecNet.Keepsakes;
public sealed class KeepsakeRoomConfig
{
public const string FileName = "keepsake-rooms.json";
public const string AllRoomsToken = "*";
public const long DefaultRoomListId = 1;
public const int DefaultRoomLimit = 10;
public const long DefaultEventId = 1;
public const string DefaultEventName = "Science Core";
public IReadOnlySet<long> RoomIds { get; init; } = new HashSet<long>();
public bool AllRooms { get; init; }
public long RoomListId { get; init; } = DefaultRoomListId;
public int RoomLimit { get; init; } = DefaultRoomLimit;
public long EventId { get; init; } = DefaultEventId;
public string EventName { get; init; } = DefaultEventName;
public bool EventEnabled { get; init; } = true;
public bool Any => AllRooms || RoomIds.Count > 0;
public bool IsKeepsakeRoom(long roomId) => AllRooms || RoomIds.Contains(roomId);
public long[] AdvertisedRooms(long roomId)
=> RoomIds.Count == 0 ? new[] { roomId } : RoomIds.OrderBy(id => id).ToArray();
public long[] ConfiguredRooms => RoomIds.OrderBy(id => id).ToArray();
public object[] RoomListEntries(long[] rooms)
=> new object[]
{
new
{
KeepsakeRoomListId = RoomListId,
ProgressionEventId = EventId,
UnlockItemAvatarItemId = (int?)null,
UnlockItemGiftDropId = (int?)null,
UnlockItemLockDurationTicks = (long?)null,
RoomUnlockStartOffsetTicks = 0L,
RoomUnlockIntervalTicks = TimeSpan.TicksPerDay,
RoomUnlockBatchSize = Math.Max(rooms.Length, 1),
RoomType = 0,
KeepsakeRoomLimit = RoomLimit,
KeepsakeRooms = rooms.Select((id, order) => new
{
KeepsakeRoomId = id, RoomId = id, KeepsakeRoomListId = RoomListId,
Type = 0, Order = order
}).ToArray(),
}
};
public static KeepsakeRoomConfig? Override { get; set; }
public static KeepsakeRoomConfig Current => Override ?? Load();
public static KeepsakeRoomConfig Load()
=> Parse(
ReadConfigFile(),
Environment.GetEnvironmentVariable("RADICADE_KEEPSAKE_ROOMS"),
Environment.GetEnvironmentVariable("RADICADE_KEEPSAKE_ROOM_LIST_ID"),
Environment.GetEnvironmentVariable("RADICADE_KEEPSAKE_ROOM_LIMIT"),
Environment.GetEnvironmentVariable("RADICADE_KEEPSAKE_EVENT_ID"),
Environment.GetEnvironmentVariable("RADICADE_KEEPSAKE_EVENT_NAME"));
public static IEnumerable<string> CandidatePaths()
=> DBConfig.AvatarCatalogDirectories()
.Select(directory => Path.Join(directory, FileName))
.Distinct(StringComparer.OrdinalIgnoreCase);
private static string? ReadConfigFile()
{
foreach (var path in CandidatePaths())
{
try
{
if (File.Exists(path)) return File.ReadAllText(path);
}
catch (IOException)
{
}
catch (UnauthorizedAccessException)
{
}
}
return null;
}
public static KeepsakeRoomConfig Parse(
string? json,
string? rooms = null,
string? roomListId = null,
string? roomLimit = null,
string? eventIdText = null,
string? eventNameText = null)
{
var allRooms = false;
var ids = new HashSet<long>();
var listId = DefaultRoomListId;
var limit = DefaultRoomLimit;
var eventId = DefaultEventId;
var eventName = DefaultEventName;
var eventEnabled = true;
if (!string.IsNullOrWhiteSpace(json))
{
try
{
using var document = JsonDocument.Parse(json);
var root = document.RootElement;
if (root.ValueKind == JsonValueKind.Array) AddIds(root, ids);
else if (root.ValueKind == JsonValueKind.Object)
{
foreach (var property in root.EnumerateObject())
{
switch (property.Name.ToLowerInvariant())
{
case "allrooms":
allRooms = IsTrue(property.Value);
break;
case "roomids" or "rooms" or "keepsakerooms":
AddIds(property.Value, ids);
break;
case "roomlistid" or "keepsakeroomlistid":
listId = ReadLong(property.Value) ?? listId;
break;
case "roomlimit" or "keepsakeroomlimit":
if (ReadLong(property.Value) is > 0 and <= int.MaxValue and var configuredLimit)
limit = (int)configuredLimit;
break;
case "eventenabled":
eventEnabled = IsTrue(property.Value);
break;
case "eventid" or "progressioneventid":
eventId = ReadLong(property.Value) ?? eventId;
break;
case "eventname" or "progressioneventname":
var name = property.Value.ValueKind == JsonValueKind.String ? property.Value.GetString() : null;
if (!string.IsNullOrWhiteSpace(name)) eventName = name!.Trim();
break;
}
}
}
}
catch (JsonException)
{
}
}
if (!string.IsNullOrWhiteSpace(rooms))
{
ids.Clear();
var text = rooms.Trim();
allRooms = text == AllRoomsToken;
if (!allRooms) AddIdsFromText(text, ids);
}
if (long.TryParse(roomListId, out var parsedListId)) listId = parsedListId;
if (int.TryParse(roomLimit, out var parsedLimit) && parsedLimit > 0) limit = parsedLimit;
if (long.TryParse(eventIdText, out var parsedEventId)) eventId = parsedEventId;
if (!string.IsNullOrWhiteSpace(eventNameText)) eventName = eventNameText.Trim();
return new KeepsakeRoomConfig
{
RoomIds = ids,
AllRooms = allRooms,
RoomListId = listId,
RoomLimit = limit,
EventId = eventId,
EventName = eventName,
EventEnabled = eventEnabled,
};
}
private static void AddIds(JsonElement element, HashSet<long> ids)
{
switch (element.ValueKind)
{
case JsonValueKind.Array:
foreach (var item in element.EnumerateArray())
{
if (ReadLong(item) is { } id) ids.Add(id);
}
break;
case JsonValueKind.String:
AddIdsFromText(element.GetString(), ids);
break;
default:
if (ReadLong(element) is { } single) ids.Add(single);
break;
}
}
private static void AddIdsFromText(string? text, HashSet<long> ids)
{
if (string.IsNullOrWhiteSpace(text)) return;
foreach (var part in text.Split(new[] { ',', ';', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
{
if (long.TryParse(part, out var id)) ids.Add(id);
}
}
private static long? ReadLong(JsonElement element) => element.ValueKind switch
{
JsonValueKind.Number when element.TryGetInt64(out var number) => number,
JsonValueKind.String when long.TryParse(element.GetString(), out var parsed) => parsed,
_ => null,
};
private static bool IsTrue(JsonElement element) => element.ValueKind switch
{
JsonValueKind.True => true,
JsonValueKind.False => false,
JsonValueKind.Number when element.TryGetInt64(out var number) => number != 0,
JsonValueKind.String => string.Equals(element.GetString()?.Trim(), "true", StringComparison.OrdinalIgnoreCase)
|| element.GetString()?.Trim() == "1",
_ => false,
};
}