diff --git a/Bot/Bot.csproj b/Bot/Bot.csproj index 88a9141..2da1cca 100644 --- a/Bot/Bot.csproj +++ b/Bot/Bot.csproj @@ -11,6 +11,7 @@ + diff --git a/Bot/Coc.cs b/Bot/Coc.cs index f17b7b8..90828fd 100644 --- a/Bot/Coc.cs +++ b/Bot/Coc.cs @@ -1,4 +1,4 @@ -using ClashOfClans; +using ClashOfClans; using ClashOfClans.Models; namespace Hyperstellar; @@ -6,50 +6,41 @@ namespace Hyperstellar; internal class Coc { - internal readonly struct DonationTuple + internal readonly struct DonationTuple(int donated, int received) { - internal readonly int Donated; - internal readonly int Received; - - public DonationTuple(int donated, int received) - { - Donated = donated; - Received = received; - } + internal readonly int Donated = donated; + internal readonly int Received = received; } - internal readonly struct ClanMemberInfo + private class ClanUtil { - internal readonly string Name; - internal readonly DonationTuple Donation; + internal readonly Dictionary Members = []; + internal readonly Clan Clan; + internal readonly IEnumerable existingMembers; - public ClanMemberInfo(string name, DonationTuple donation) + public ClanUtil(Clan clan) { - Name = name; - Donation = donation; + foreach (var member in clan.MemberList!) + { + Members[member.Tag] = member; + } + Clan = clan; + existingMembers = clan.MemberList!.Intersect(_prevClan.Clan.MemberList!, new MemberComparer()); } - - internal readonly int Donated => Donation.Donated; - internal readonly int Received => Donation.Received; } - private readonly struct ClanInfo + private class MemberComparer : IEqualityComparer { - internal readonly Dictionary Members = new(); + public bool Equals(ClanMember? x, ClanMember? y) => x!.Tag.Equals(y!.Tag); - public ClanInfo(Clan clan) - { - foreach (var member in clan.MemberList!) - { - DonationTuple donation = new(member.Donations, member.DonationsReceived); - Members[member.Tag] = new(member.Name, donation); - } - } + public int GetHashCode(ClanMember obj) => obj.Tag.GetHashCode(); } const string CLAN_ID = "#2QU2UCJJC"; const string DIM_ID = "#28QL0CJV2"; - private static ClanInfo _prevClan; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + private static ClanUtil _prevClan; +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. internal static readonly ClashOfClansClient Client = new(Secrets.Coc); private static async Task GetClanAsync() => await Client.Clans.GetClanAsync(CLAN_ID); @@ -57,24 +48,25 @@ public ClanInfo(Clan clan) private static async Task PollAsync() { var clan = await GetClanAsync(); - ClanInfo clanInfo = new(clan); - await CheckDonations(clanInfo, clan); - _prevClan = clanInfo; + if (clan == null) return; + if (clan.MemberList == null) return; + ClanUtil clanUtil = new(clan); + await CheckDonations(clanUtil); + + _prevClan = clanUtil; } - private static async Task CheckDonations(ClanInfo clan, Clan c) + private static async Task CheckDonations(ClanUtil clan) { - Dictionary donationsDelta = new(); - foreach (var memberTag in clan.Members.Keys) + Dictionary donationsDelta = []; + var existingMemberTags = clan.existingMembers.Select(x => x.Tag); + foreach (var tag in existingMemberTags) { - bool existsInPrevClan = _prevClan.Members.TryGetValue(memberTag, out ClanMemberInfo previous); - if (existsInPrevClan) + var current = clan.Members[tag]; + var previous = _prevClan.Members[tag]; + if (current.Donations > previous.Donations || current.DonationsReceived > previous.DonationsReceived) { - ClanMemberInfo current = clan.Members[memberTag]; - if (current.Donated > previous.Donated || current.Received > previous.Received) - { - donationsDelta[current.Name] = new(current.Donated - previous.Donated, current.Received - previous.Received); - } + donationsDelta[current.Name] = new(current.Donations - previous.Donations, current.DonationsReceived - previous.DonationsReceived); } } if (donationsDelta.Count > 0) @@ -83,10 +75,7 @@ private static async Task CheckDonations(ClanInfo clan, Clan c) } } - internal static async Task InitAsync() - { - _prevClan = new(await GetClanAsync()); - } + internal static async Task InitAsync() => _prevClan = new(await GetClanAsync()); internal static async Task BotReadyAsync() { diff --git a/Bot/Discord.cs b/Bot/Discord.cs index 2027b53..e1212b6 100644 --- a/Bot/Discord.cs +++ b/Bot/Discord.cs @@ -12,7 +12,7 @@ internal class Discord const ulong BOT_LOG_ID = 1099026457268863017; #endif - private static DiscordSocketClient _bot = new(); + private static readonly DiscordSocketClient _bot = new(); #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. private static SocketTextChannel _botLog; #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. @@ -26,7 +26,7 @@ private static Task Log(LogMessage msg) private static Task Ready() { _botLog = (SocketTextChannel)_bot.GetChannel(BOT_LOG_ID); - Task.Run(Coc.BotReadyAsync); + Task.Run(BotReadyAsync); return Task.CompletedTask; } diff --git a/Bot/Program.cs b/Bot/Program.cs index 5028ef8..7170c59 100644 --- a/Bot/Program.cs +++ b/Bot/Program.cs @@ -1,11 +1,12 @@ -using Hyperstellar; - -public class Program +namespace Hyperstellar { - public static async Task Main(string[] args) + public class Program { - await Hyperstellar.Discord.InitAsync(); - await Coc.InitAsync(); - await Task.Delay(-1); + public static async Task Main() + { + await Discord.InitAsync(); + await Coc.InitAsync(); + await Task.Delay(-1); + } } } \ No newline at end of file diff --git a/Bot/Sql/Db.cs b/Bot/Sql/Db.cs new file mode 100644 index 0000000..4474ae4 --- /dev/null +++ b/Bot/Sql/Db.cs @@ -0,0 +1,9 @@ +using SQLite; + +namespace Hyperstellar.Sql +{ + internal class Db + { + private static readonly SQLiteConnection _db = new("Hyperstellar.db"); + } +}